#include "tpe_term.h"
#include <cmath>

int Tpe_term::Tri(int &j2a, int &j2b, int &j2c) {
  // I+J>=K, I+K>=J, J+K>=I,
  // I/2+J/2+K/2 = INTEGER.
  // TRI=1, WHEN TRIADIC CONDITION IS FULFILLED, TRI=-1 OTHERWISE
  int L2 = j2a + j2b + j2c;
  if (int(L2) != (L2 / 2) * 2)
    return -1;
  L2 = L2 / 2;
  if (j2a * j2b * j2c < 0)
    return -1;
  if ((L2 - j2a) * (L2 - j2b) * (L2 - j2c) < 0)
    return -1;
  return 1;
}

void Tpe_term::init_cgInt(int J2max) {
  cg_J2max = J2max;
  JaJbJ_t.init(J2max);
  int size = JaJbJ_t.state.size();
  /*
  for(int i=0; i<size; i++){
    cout<<i<<"\t"<<JaJbJ_t.state[i].j2a<<"\t";
    cout<<JaJbJ_t.state[i].j2b<<"\t";
    cout<<JaJbJ_t.state[i].J2<<"\t"<<endl;
  }*/
  for (int i = 0; i < size; i++) {
    int j2a = JaJbJ_t.state[i].j2a;
    int j2b = JaJbJ_t.state[i].j2b;
    int J2 = JaJbJ_t.state[i].J2;
    int M = 0;
    double t = cg.cal(j2a, j2b, J2, M, M, M);
    cg_IntZero.push_back(t);
  }
}

double Tpe_term::cg_int(int ja, int jb, int J) {
  int j2a = ja * 2;
  int j2b = jb * 2;
  int J2 = J * 2;

  if (std::max(j2a, j2b) > cg_J2max) {
    cout << " Jmax in init_cgInt should be bigger !!! " << endl;
    exit(0);
  }

  if (Tri(j2a, j2b, J2) == -1)
    return 0.0;
  int index = JaJbJ_t.vec[j2a][j2b][J2];
  // cout << "JaJbJ_t index = " << index << endl;
  return cg_IntZero[index];
}

void Tpe_term::BinoHat_init(int lmax) {
  bino_lmax = lmax;
  int nmax = 2 * lmax + 8;
  bino.init(nmax);
  BioHat.resize(lmax + 1);
  //  for(int i=0; i<bino.facvec.size();i++)
  //    cout<<i<<"\t"<<bino.facvec[i]<<endl;
  for (int lbar = 0; lbar <= lmax; lbar++) {
    BioHat[lbar].resize(lbar + 1);
    for (int i3 = 0; i3 <= lbar; i3++) {
      int i4 = lbar - i3;
      int n = 2 * lbar + 1;
      int k1 = 2 * i3;
      int k2 = 2 * i4;
      double t = bino.facvec[n] / (bino.facvec[k1] * bino.facvec[k2] * 1.0);
      BioHat[lbar][i3] = std::sqrt(t);
      // cout<<lbar<<"\t"<<i3<<"\t"<<BioHat[lbar][i3]<<"\t"<<t<<endl;
    }
  }
}

void Tpe_term::init(vector<vector<int>> Jaco_l123_info, vector<int> Jaco_E_info,
                    int jaco_J12_2max, int jaco_j3_2max) {
  //
  pf_tpe_c1 = 16 * (std::pow(hbarc, 4)) * (LECs.LEC_gA * LECs.LEC_gA) *
              LECs.LEC_C1 * (Mpic2 * Mpic2);
  pf_tpe_c1 = pf_tpe_c1 / (1000 * std::pow(2 * Pi, 4) * std::pow(F_pi, 4));
  // cout << "pf_tpe_c1 = " << pf_tpe_c1 << endl;

  pf_tpe_c3 = 8 * std::sqrt(3) * LECs.LEC_C3 * (LECs.LEC_gA * LECs.LEC_gA) *
              std::pow(hbarc, 6);
  pf_tpe_c3 = pf_tpe_c3 / (1000 * std::pow(2 * Pi, 4) * std::pow(F_pi, 4));
  // cout << "pf_tpe_c3 = " << pf_tpe_c3 << endl;

  pf_tpe_c4 = 144 * std::sqrt(3) * LECs.LEC_C4 * (LECs.LEC_gA * LECs.LEC_gA) *
              std::pow(hbarc, 6);
  pf_tpe_c4 = pf_tpe_c4 / (1000 * std::pow(2 * Pi, 4) * std::pow(F_pi, 4));
  // cout << "pf_tpe_c4 = " << pf_tpe_c4 << endl;

  // initial < ja,0 jb,0 | J,0>
  init_cgInt(40);
  // cout << cg_int(5, 5, 8) << endl;
  // initial sqrt{ (2l+1)!/( (2*i1)!(2*i2)! ) }
  BinoHat_init(20);
  // cout<<tpe_t.bino.facvec[5]<<"\t"<<tpe_t.BioHat[8][4]<<endl;

  // initial Hat_vec;
  Hat_vec.resize(50);
  cout << "TPE_term start to init" << endl;
#pragma omp parallel for schedule(dynamic, 1)
  for (int i = 0; i < 50; i++) {
    double t = 2 * i + 1;
    Hat_vec[i] = std::sqrt(t);
  }

  // initial TS_sixJ
  T1S_sixJ.resize(2);
  for (int T12p = 0; T12p <= 1; T12p++) {
    T1S_sixJ[T12p].resize(2);
    for (int T12 = 0; T12 <= 1; T12++) {
      T1S_sixJ[T12p][T12].resize(2);
      int T12p_2 = 2 * T12p;
      int T12_2 = 2 * T12;
      double T1 = sixJ.quick(T12p_2, T12_2, 2, 1, 1, 1) *
                  sixJ.quick(T12p_2, T12_2, 2, 1, 1, 1);
      for (int S12p = 0; S12p <= 1; S12p++) {
        T1S_sixJ[T12p][T12][S12p].resize(2);
        for (int S12 = 0; S12 <= 1; S12++) {
          int S12p_2 = S12p * 2;
          int S12_2 = S12 * 2;
          double T2 = sixJ.quick(1, 1, 2, S12_2, S12p_2, 1);
          T1S_sixJ[T12p][T12][S12p][S12] = T1 * T2;
        }
      }
    }
  }
  T3S_sixJ.resize(2);
  double T1 = sixJ.quick(2, 2, 2, 1, 1, 1) * sixJ.quick(2, 2, 2, 1, 1, 3);
  for (int S12p = 0; S12p <= 1; S12p++) {
    T3S_sixJ[S12p].resize(2);
    for (int S12 = 0; S12 <= 1; S12++) {
      int S12p_2 = S12p * 2;
      int S12_2 = S12 * 2;
      double T2 = sixJ.quick(1, 1, 2, S12_2, S12p_2, 1);
      T3S_sixJ[S12p][S12] = T1 * T2;
    }
  }
  // cout<<"good? 0"<<endl;
  // double T = sixJ.quick(0, 2, 2, 1, 1, 2);
  T1_69J.resize(2);
  for (int T12p = 0; T12p <= 1; T12p++) {
    T1_69J[T12p].resize(2);
    for (int T12 = 0; T12 <= 1; T12++) {
      // cout << T12p << "\t" << T12 << endl;
      double T = sixJ.cal(2 * T12p, 2 * T12, 2, 1, 1, 1);
      T = T * ninJ.cal(1, 1, 2, 1, 1, 2, 2 * T12p, 2 * T12, 2);
      T1_69J[T12p][T12] = T;
    }
  }
  T3_69J = sixJ.quick(2, 2, 2, 1, 1, 3);
  T3_69J = T3_69J * ninJ.quick(1, 1, 2, 1, 1, 2, 2, 2, 2);
  // cout << "good? 1 " << endl;
  S12_9J.resize(2);
  for (int S12p = 0; S12p <= 1; S12p++) {
    S12_9J[S12p].resize(2);
    for (int S12 = 0; S12 <= 1; S12++) {
      S12_9J[S12p][S12].resize(3);
      for (int s_0 = 0; s_0 <= 2; s_0++) {
        S12_9J[S12p][S12][s_0] =
            ninJ.quick(1, 1, 2, 1, 1, 2, 2 * S12p, 2 * S12, 2 * s_0);
      }
    }
  }
  // cout << "good? 2" << endl;
  /*
  for(int T12p=0; T12p<=1; T12p++){
    for(int T12=0; T12<=1; T12++){
      for(int S12p=0; S12p<=1; S12p++){
        for(int S12=0; S12<=1; S12++){
          cout<<T12p<<"\t"<<T12<<"\t"<<S12p<<"\t"<<S12<<"\t\t"<<T1S_sixJ[T12p][T12][S12p][S12]<<endl;
        }
      }
    }
  }
  for(int S12p=0; S12p<=1; S12p++){
    for(int S12=0; S12<=1; S12++){
      cout<<S12p<<"\t"<<S12<<"\t\t"<<T3S_sixJ[S12p][S12]<<endl;
    }
  }
  */
  // initial l_state & l_vec

  //  int lmax = jaco_lmax;
  int l12p_min = Jaco_l123_info[0][0];
  int l12p_max = Jaco_l123_info[0][1];
  int l3p_min = Jaco_l123_info[0][2];
  int l3p_max = Jaco_l123_info[0][3];

  int l12_min = Jaco_l123_info[1][0];
  int l12_max = Jaco_l123_info[1][1];
  int l3_min = Jaco_l123_info[1][2];
  int l3_max = Jaco_l123_info[1][3];

  int Emin_F = Jaco_E_info[0];
  int Emax_F = Jaco_E_info[1];
  int Emin_I = Jaco_E_info[2];
  int Emax_I = Jaco_E_info[3];

  /*cout << "l12p_min : " << l12p_min << "\t l12p_max : " << l12p_max
       << "\t l3p_min : " << l3p_min << "\t l3p_max : " << l3p_max << endl;
  cout << "l12_min : " << l12_min << "\t l12_max : " << l12_max
       << "\t l3_min : " << l3_min << "\t l3_max : " << l3_max << endl;  */

  l_vec.resize(l12p_max + 1);
  for (int l12p = l12p_min; l12p <= l12p_max; l12p++) {
    l_vec[l12p].resize(l12_max + 1);
    for (int l12 = l12_min; l12 <= l12_max; l12++) {
      l_vec[l12p][l12].resize(l3p_max + 1);
      for (int l3p = l3p_min; l3p <= l3p_max; l3p++) {
        l_vec[l12p][l12][l3p].resize(l3_max + 1);
        for (int l3 = l3_min; l3 <= l3_max; l3++) {

          l_vec[l12p][l12][l3p][l3] = -1;
        }
      }
    }
  }
  // cout << "good? 0" << endl;
  int index = 0;
  l_struct l_state_t;
  for (int l12p = l12p_min; l12p <= l12p_max; l12p++) {
    for (int l12 = l12_min; l12 <= l12_max; l12++) {
      for (int l3p = l3p_min; l3p <= l3p_max; l3p++) {
        for (int l3 = l3_min; l3 <= l3_max; l3++) {
          if ((l12p + l3p) > Emax_F)
            continue;
          if ((l12 + l3) > Emax_I)
            continue;
          l_vec[l12p][l12][l3p][l3] = index;
          l_state_t.l12p = l12p;
          l_state_t.l12 = l12;
          l_state_t.l3p = l3p;
          l_state_t.l3 = l3;
          l_state.push_back(l_state_t);
          index++;
        }
      }
    }
  }
  /*std::ofstream file;
  file.open("data/l_state.dat");
  for (int i = 0; i < l_state.size(); i++) {
    file << i << "\t" << l_state[i].l12p;
    file << "\t" << l_state[i].l12;
    file << "\t" << l_state[i].l3p;
    file << "\t" << l_state[i].l3 << endl;
  }
  file.close(); */

  // init t014_state & t014_vec
  // Caution !!!! t_max
  // int j2max = std::min(jaco_J12_2max,
  //                     jaco_j3_2max); // j2max is the max val j in S.P. orbits
  // int t_max = j2max;
  //
  /*
  t014_vec.resize(t_max + 1);
  for (int t0 = 0; t0 <= t_max; t0++) {
    int tx_max = t0 + 1;
    t014_vec[t0].resize(tx_max + 2);
    for (int t1 = 0; t1 <= tx_max; t1++) {
      t014_vec[t0][t1].resize(tx_max + 2);
      for (int t4 = 0; t4 <= tx_max; t4++) {
        t014_vec[t0][t1][t4] = -1;
      }
    }
  }
  // cout<<"good?"<<endl;
  t014_struct t014_state_t;
  index = 0;
  for (int t0 = 0; t0 <= t_max; t0++) {
    int tx_min = std::abs(t0 - 1);
    int tx_max = t0 + 1;
    for (int t1 = tx_min; t1 <= tx_max; t1++) {
      for (int t4 = tx_min; t4 <= tx_max; t4++) {
        t014_state_t.t_0 = t0;
        t014_state_t.t_1 = t1;
        t014_state_t.t_4 = t4;
        t014_state.push_back(t014_state_t);
        t014_vec[t0][t1][t4] = index;
        index++;
      }
    }
  }
  cout << "t014 all size = " << index << endl;
  */
  // init t014_state2 & t014_vec2
  // int t_max = j2max * 2 + 4;
  //  cout << "good? 1" << endl;
  int t_max = std::min(jaco_J12_2max, jaco_j3_2max);
  // j2max is the max val j in S.P. orbits
  int size_l = l_state.size();

  t014_vec2.resize(size_l);
  // cout << "good? 1 - 1 size_l = " << size_l << "\t t_max = " << t_max <<
  // endl;
  for (int l = 0; l < size_l; l++) {
    t014_vec2[l].resize(t_max + 1);
    for (int t0 = 0; t0 <= t_max; t0++) {
      int tx_max = t0 + 1;
      t014_vec2[l][t0].resize(tx_max + 1);
      for (int t1 = 0; t1 <= tx_max; t1++) {
        t014_vec2[l][t0][t1].resize(tx_max + 1);
        for (int t4 = 0; t4 <= tx_max; t4++) {
          t014_vec2[l][t0][t1][t4] = -1;
        }
      }
    }
  }
  // cout << "good? 2" << endl;
  // t014_struct t014_state_t;
  t014_struct t014_state_t;
  int index2 = 0;

  t014_state2.resize(size_l);

  for (int l = 0; l < size_l; l++) {

    int t1_min_A = std::abs(l_state[l].l12p - l_state[l].l12);
    int t1_max_A = l_state[l].l12p + l_state[l].l12;
    int t4_min_A = std::abs(l_state[l].l3p - l_state[l].l3);
    int t4_max_A = l_state[l].l3p + l_state[l].l3;

    index = 0;

    for (int t0 = 0; t0 <= t_max; t0++) {
      int t1_min_B = std::abs(t0 - 1);
      int t1_max_B = t0 + 1;
      int t4_min_B = t1_min_B;
      int t4_max_B = t1_max_B;
      int t1_min = std::max(t1_min_A, t1_min_B);
      int t1_max = std::min(t1_max_A, t1_max_B);

      int t4_min = std::max(t4_min_A, t4_min_B);
      int t4_max = std::min(t4_max_A, t4_max_B);
      if (t1_min > t1_max)
        continue;
      for (int t1 = t1_min; t1 <= t1_max; t1++) {
        if (t4_min > t4_max)
          continue;
        for (int t4 = t4_min; t4 <= t4_max; t4++) {
          t014_state_t.t_0 = t0;
          t014_state_t.t_1 = t1;
          t014_state_t.t_4 = t4;
          t014_state2[l].push_back(t014_state_t);
          t014_vec2[l][t0][t1][t4] = index;
          index++;
          index2++;
        }
      }
    }
  }
  // cout << "t014_2 all size = " << index2 << endl;
  /*std::ofstream file2;
  file2.open("data/t014_2.dat");
  for (int l = 0; l < l_state.size(); l++) {
    file2 << endl;
    file2 << "l_index = " << l << endl;
    file2 << "index\t t0\t t1\t t2" << endl;
    for (int i = 0; i < t014_state2[l].size(); i++) {
      file2 << i << "\t" << t014_state2[l][i].t_0;
      file2 << "\t" << t014_state2[l][i].t_1;
      file2 << "\t" << t014_state2[l][i].t_4 << endl;
    }
  }
  file2.close(); */
  // cout<<"Test t014_vec2 = "<<
  // cout << "TPE Ic1_init" << endl;

  Ic1_init();
  // cout << "Ic1 finished" << endl;
  // Hc1_init();
  // cout << "Hc1 finished" << endl;
  Ic3_init();
  // cout << "Ic3 finished" << endl;
  // Hc3_init();
  // cout << "Hc3 finished" << endl;
  Ic4_init();
  // cout << "Ic4 finished" << endl;
  // Hc4_init();
  // cout << "Hc4 finished" << endl;

  // cout << "Hc lbar Max = " << this->lbar123_max << endl;
}

void Tpe_term::init_II(vector<vector<int>> Jaco_l123_info,
                       vector<int> Jaco_E_info, vector<vector<int>> E_Jac_conf,
                       int jaco_J12_2max, int jaco_j3_2max) {
  //
  pf_tpe_c1 = 16 * (std::pow(hbarc, 4)) * (LECs.LEC_gA * LECs.LEC_gA) *
              LECs.LEC_C1 * (Mpic2 * Mpic2);
  pf_tpe_c1 = pf_tpe_c1 / (1000 * std::pow(2 * Pi, 4) * std::pow(F_pi, 4));
  // cout << "pf_tpe_c1 = " << pf_tpe_c1 << endl;

  pf_tpe_c3 = 8 * std::sqrt(3) * LECs.LEC_C3 * (LECs.LEC_gA * LECs.LEC_gA) *
              std::pow(hbarc, 6);
  pf_tpe_c3 = pf_tpe_c3 / (1000 * std::pow(2 * Pi, 4) * std::pow(F_pi, 4));
  // cout << "pf_tpe_c3 = " << pf_tpe_c3 << endl;

  pf_tpe_c4 = 144 * std::sqrt(3) * LECs.LEC_C4 * (LECs.LEC_gA * LECs.LEC_gA) *
              std::pow(hbarc, 6);
  pf_tpe_c4 = pf_tpe_c4 / (1000 * std::pow(2 * Pi, 4) * std::pow(F_pi, 4));
  // cout << "pf_tpe_c4 = " << pf_tpe_c4 << endl;

  // initial < ja,0 jb,0 | J,0>
  init_cgInt(40);
  // cout << cg_int(5, 5, 8) << endl;
  // initial sqrt{ (2l+1)!/( (2*i1)!(2*i2)! ) }
  BinoHat_init(20);
  // cout<<tpe_t.bino.facvec[5]<<"\t"<<tpe_t.BioHat[8][4]<<endl;

  // initial Hat_vec;
  Hat_vec.resize(50);
  cout << "TPE_term start to init" << endl;
#pragma omp parallel for schedule(dynamic, 1)
  for (int i = 0; i < 50; i++) {
    double t = 2 * i + 1;
    Hat_vec[i] = std::sqrt(t);
  }

  // initial TS_sixJ
  T1S_sixJ.resize(2);
  for (int T12p = 0; T12p <= 1; T12p++) {
    T1S_sixJ[T12p].resize(2);
    for (int T12 = 0; T12 <= 1; T12++) {
      T1S_sixJ[T12p][T12].resize(2);
      int T12p_2 = 2 * T12p;
      int T12_2 = 2 * T12;
      double T1 = sixJ.quick(T12p_2, T12_2, 2, 1, 1, 1) *
                  sixJ.quick(T12p_2, T12_2, 2, 1, 1, 1);
      for (int S12p = 0; S12p <= 1; S12p++) {
        T1S_sixJ[T12p][T12][S12p].resize(2);
        for (int S12 = 0; S12 <= 1; S12++) {
          int S12p_2 = S12p * 2;
          int S12_2 = S12 * 2;
          double T2 = sixJ.quick(1, 1, 2, S12_2, S12p_2, 1);
          T1S_sixJ[T12p][T12][S12p][S12] = T1 * T2;
        }
      }
    }
  }
  T3S_sixJ.resize(2);
  double T1 = sixJ.quick(2, 2, 2, 1, 1, 1) * sixJ.quick(2, 2, 2, 1, 1, 3);
  for (int S12p = 0; S12p <= 1; S12p++) {
    T3S_sixJ[S12p].resize(2);
    for (int S12 = 0; S12 <= 1; S12++) {
      int S12p_2 = S12p * 2;
      int S12_2 = S12 * 2;
      double T2 = sixJ.quick(1, 1, 2, S12_2, S12p_2, 1);
      T3S_sixJ[S12p][S12] = T1 * T2;
    }
  }
  // cout<<"good? 0"<<endl;
  // double T = sixJ.quick(0, 2, 2, 1, 1, 2);
  T1_69J.resize(2);
  for (int T12p = 0; T12p <= 1; T12p++) {
    T1_69J[T12p].resize(2);
    for (int T12 = 0; T12 <= 1; T12++) {
      // cout << T12p << "\t" << T12 << endl;
      double T = sixJ.cal(2 * T12p, 2 * T12, 2, 1, 1, 1);
      T = T * ninJ.cal(1, 1, 2, 1, 1, 2, 2 * T12p, 2 * T12, 2);
      T1_69J[T12p][T12] = T;
    }
  }
  T3_69J = sixJ.quick(2, 2, 2, 1, 1, 3);
  T3_69J = T3_69J * ninJ.quick(1, 1, 2, 1, 1, 2, 2, 2, 2);
  // cout << "good? 1 " << endl;
  S12_9J.resize(2);
  for (int S12p = 0; S12p <= 1; S12p++) {
    S12_9J[S12p].resize(2);
    for (int S12 = 0; S12 <= 1; S12++) {
      S12_9J[S12p][S12].resize(3);
      for (int s_0 = 0; s_0 <= 2; s_0++) {
        S12_9J[S12p][S12][s_0] =
            ninJ.quick(1, 1, 2, 1, 1, 2, 2 * S12p, 2 * S12, 2 * s_0);
      }
    }
  }
  // cout << "good? 2" << endl;
  /*
  for(int T12p=0; T12p<=1; T12p++){
    for(int T12=0; T12<=1; T12++){
      for(int S12p=0; S12p<=1; S12p++){
        for(int S12=0; S12<=1; S12++){
          cout<<T12p<<"\t"<<T12<<"\t"<<S12p<<"\t"<<S12<<"\t\t"<<T1S_sixJ[T12p][T12][S12p][S12]<<endl;
        }
      }
    }
  }
  for(int S12p=0; S12p<=1; S12p++){
    for(int S12=0; S12<=1; S12++){
      cout<<S12p<<"\t"<<S12<<"\t\t"<<T3S_sixJ[S12p][S12]<<endl;
    }
  }
  */
  // initial l_state & l_vec

  //  int lmax = jaco_lmax;
  int l12p_min = Jaco_l123_info[0][0];
  int l12p_max = Jaco_l123_info[0][1];
  int l3p_min = Jaco_l123_info[0][2];
  int l3p_max = Jaco_l123_info[0][3];

  int l12_min = Jaco_l123_info[1][0];
  int l12_max = Jaco_l123_info[1][1];
  int l3_min = Jaco_l123_info[1][2];
  int l3_max = Jaco_l123_info[1][3];

  int Emin_F = Jaco_E_info[0];
  int Emax_F = Jaco_E_info[1];
  int Emin_I = Jaco_E_info[2];
  int Emax_I = Jaco_E_info[3];

  /*cout << "l12p_min : " << l12p_min << "\t l12p_max : " << l12p_max
       << "\t l3p_min : " << l3p_min << "\t l3p_max : " << l3p_max << endl;
  cout << "l12_min : " << l12_min << "\t l12_max : " << l12_max
       << "\t l3_min : " << l3_min << "\t l3_max : " << l3_max << endl; */

  l_vec.resize(l12p_max + 1);
  for (int l12p = l12p_min; l12p <= l12p_max; l12p++) {
    l_vec[l12p].resize(l12_max + 1);
    for (int l12 = l12_min; l12 <= l12_max; l12++) {
      l_vec[l12p][l12].resize(l3p_max + 1);
      for (int l3p = l3p_min; l3p <= l3p_max; l3p++) {
        l_vec[l12p][l12][l3p].resize(l3_max + 1);
        for (int l3 = l3_min; l3 <= l3_max; l3++) {

          l_vec[l12p][l12][l3p][l3] = -1;
        }
      }
    }
  }
  // cout << "good? 0" << endl;
  int index = 0;
  l_struct l_state_t;
  for (int l12p = l12p_min; l12p <= l12p_max; l12p++) {
    for (int l12 = l12_min; l12 <= l12_max; l12++) {
      for (int l3p = l3p_min; l3p <= l3p_max; l3p++) {
        for (int l3 = l3_min; l3 <= l3_max; l3++) {
          if ((l12p + l3p) > Emax_F)
            continue;
          if ((l12 + l3) > Emax_I)
            continue;
          int Par_P = this->phase(l12p + l3p);
          int Par = this->phase(l12 + l3);
          if (Par != Par_P)
            continue;
          l_vec[l12p][l12][l3p][l3] = index;
          l_state_t.l12p = l12p;
          l_state_t.l12 = l12;
          l_state_t.l3p = l3p;
          l_state_t.l3 = l3;
          l_state.push_back(l_state_t);
          index++;
        }
      }
    }
  }
  if (TpeCom.rank() == 0) {
    std::ofstream file;
    file.open("data/l_state.dat");
    for (int i = 0; i < l_state.size(); i++) {
      file << i << "\t" << l_state[i].l12p;
      file << "\t" << l_state[i].l12;
      file << "\t" << l_state[i].l3p;
      file << "\t" << l_state[i].l3 << endl;
    }
    file.close();
  }
  // ------ ------ Distribute Tasks & Reduce l_state, l_vec ------ Start -----//
  this->Jlpl_build(Emax_F, Emax_I, E_Jac_conf, this->l_state, this->l_vec,
                   this->Jlpl, this->Jlpl_mpi_task_all,
                   this->Jlpl_mpi_task_dis);
  if (TpeCom.rank() == 0) {
    std::ofstream file;
    file.open("data/l_state_reduced.dat");
    file << "i\t l12p\t l3p\t l12\t l3" << endl;
    for (int i = 0; i < l_state.size(); i++) {
      file << i << "\t" << l_state[i].l12p;
      file << "\t" << l_state[i].l3p;
      file << "\t" << l_state[i].l12;
      file << "\t" << l_state[i].l3 << endl;
    }
    file.close();
  }
  // ------ ------ Distribute Tasks & Reduce l_state, l_vec ------ End -----//
  // ------ init t014_state2 & t014_vec2 ----- Start ------ //
  // int t_max = j2max * 2 + 4;
  //  cout << "good? 1" << endl;
  int t_max = std::min(jaco_J12_2max, jaco_j3_2max);

  // j2max is the max val j in S.P. orbits
  int size_l = l_state.size();

  t014_vec2.resize(size_l);
  cout << "good? 1 - 1 size_l = " << size_l << "\t t_max = " << t_max << endl;
  for (int l = 0; l < size_l; l++) {
    t014_vec2[l].resize(t_max + 1);
    for (int t0 = 0; t0 <= t_max; t0++) {
      int tx_max = t0 + 1;
      t014_vec2[l][t0].resize(tx_max + 1);
      for (int t1 = 0; t1 <= tx_max; t1++) {
        t014_vec2[l][t0][t1].resize(tx_max + 1);
        for (int t4 = 0; t4 <= tx_max; t4++) {
          t014_vec2[l][t0][t1][t4] = -1;
        }
      }
    }
  }
  // cout << "good? 2" << endl;
  // t014_struct t014_state_t;
  t014_struct t014_state_t;
  int index2 = 0;

  t014_state2.resize(size_l);

  for (int l = 0; l < size_l; l++) {

    int t1_min_A = std::abs(l_state[l].l12p - l_state[l].l12);
    int t1_max_A = l_state[l].l12p + l_state[l].l12;
    int t4_min_A = std::abs(l_state[l].l3p - l_state[l].l3);
    int t4_max_A = l_state[l].l3p + l_state[l].l3;

    index = 0;

    for (int t0 = 0; t0 <= t_max; t0++) {
      int t1_min_B = std::abs(t0 - 1);
      int t1_max_B = t0 + 1;
      int t4_min_B = t1_min_B;
      int t4_max_B = t1_max_B;
      int t1_min = std::max(t1_min_A, t1_min_B);
      int t1_max = std::min(t1_max_A, t1_max_B);

      int t4_min = std::max(t4_min_A, t4_min_B);
      int t4_max = std::min(t4_max_A, t4_max_B);
      if (t1_min > t1_max)
        continue;
      for (int t1 = t1_min; t1 <= t1_max; t1++) {
        if (t4_min > t4_max)
          continue;
        for (int t4 = t4_min; t4 <= t4_max; t4++) {
          t014_state_t.t_0 = t0;
          t014_state_t.t_1 = t1;
          t014_state_t.t_4 = t4;
          t014_state2[l].push_back(t014_state_t);
          t014_vec2[l][t0][t1][t4] = index;
          index++;
          index2++;
        }
      }
    }
  }
  // ------ init t014_state2 & t014_vec2 ----- End ------ //
  // cout << "t014_2 all size = " << index2 << endl;
  /*std::ofstream file2;
  file2.open("data/t014_2.dat");
  for (int l = 0; l < l_state.size(); l++) {
    file2 << endl;
    file2 << "l_index = " << l << endl;
    file2 << "index\t t0\t t1\t t2" << endl;
    for (int i = 0; i < t014_state2[l].size(); i++) {
      file2 << i << "\t" << t014_state2[l][i].t_0;
      file2 << "\t" << t014_state2[l][i].t_1;
      file2 << "\t" << t014_state2[l][i].t_4 << endl;
    }
  }
  file2.close(); */
  // cout<<"Test t014_vec2 = "<<
  // cout << "TPE Ic1_init" << endl;

  Ic1_init();
  // cout << "Ic1 finished" << endl;
  // Hc1_init();
  // cout << "Hc1 finished" << endl;
  Ic3_init();
  // cout << "Ic3 finished" << endl;
  // Hc3_init();
  // cout << "Hc3 finished" << endl;
  Ic4_init();
  // cout << "Ic4 finished" << endl;
  // Hc4_init();
  // cout << "Hc4 finished" << endl;

  // cout << "Hc lbar Max = " << this->lbar123_max << endl;
}

void Tpe_term::Ic1_init() {

  /*
  for(int i=0; i<l_state.size(); i++)
    cout<<i<<"\t"<<l_state[i].l12p<<"\t"<<l_state[i].l12
      <<"\t"<<l_state[i].l3p<<"\t"<<l_state[i].l3<<endl;
  cout<<"$$$ \t "<<l_vec[3][2][0][5]<<endl;
  */

  int size_l = l_state.size();
  // double C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12;

  Ic1_index.resize(size_l);
  // Ic1_val.resize(size_l);
  // Ic1_val2.resize(size_l);

  vector<double> Ic1_val2_t;
  Ic1_val2_t.resize(13);
  int index = 0;
// int index = 0;
#pragma omp parallel for schedule(dynamic, 1)
  for (int l_index = 0; l_index < size_l; l_index++) {
    Ic_struct Ic1_t;
    int l12p = l_state[l_index].l12p;
    int l12 = l_state[l_index].l12;
    int l3p = l_state[l_index].l3p;
    int l3 = l_state[l_index].l3;

    //
    for (int lamb_1 = 0; lamb_1 <= 1; lamb_1++) {
      int lamb_2 = 1 - lamb_1;
      double C1 = Hat_vec[lamb_1] * Hat_vec[lamb_2] * phase(lamb_1);
      if (lamb_2 == 1) {
        C1 = C1 / (std::sqrt(3));
      }
      // cout<<"C1 = "<<C1<<endl;
      //
      for (int lamb_i = 0; lamb_i <= lamb_1; lamb_i++) {
        int lamb_j = lamb_1 - lamb_i;
        int q1_min = std::abs(l12p - lamb_i);
        int q1_max = l12p + lamb_i;
        int q2_min = std::abs(l12 - lamb_j);
        int q2_max = l12 + lamb_j;
        double C2 = phase(lamb_j) * BinoHat_cal(lamb_1, lamb_i);
        //
        for (int q1 = q1_min; q1 <= q1_max; q1++) {
          // if (phase(q1 + lamb_i + l12p) != 1)
          // continue;
          double C3 = Hat_vec[q1] * cg_int(lamb_i, q1, l12p);
          if (C3 == 0.0)
            continue;
          // cout<<"C3 = "<<C3<<endl;
          //
          for (int q2 = q2_min; q2 <= q2_max; q2++) {
            // if (phase(q2 + lamb_j + l12) != 1)
            // continue;
            double C4 = phase(q2) * Hat_vec[q2] * cg_int(lamb_j, q2, l12);
            if (C4 == 0.0)
              continue;
            // cout<<"C4 = "<<C4<<endl;
            //
            for (int lamb_3 = 0; lamb_3 <= 1; lamb_3++) {
              int lamb_4 = 1 - lamb_3;
              double C5 = phase(lamb_4) * Hat_vec[lamb_3] * Hat_vec[lamb_4];
              //
              for (int lamb_k = 0; lamb_k <= lamb_2; lamb_k++) {
                int lamb_l = lamb_2 - lamb_k;
                int lamb_12min = std::abs(1 - lamb_2);
                int lamb_12max = 1 + lamb_2;
                int lamb_3kmin = std::abs(lamb_3 - lamb_k);
                int lamb_3kmax = lamb_3 + lamb_k;
                int lamb_4lmin = std::abs(lamb_4 - lamb_l);
                int lamb_4lmax = lamb_4 + lamb_l;
                double C6 = phase(lamb_l) * BinoHat_cal(lamb_2, lamb_k);
                // cout<<"C6 = "<<C6<<endl;
                //
                for (int lamb_12 = lamb_12min; lamb_12 <= lamb_12max;
                     lamb_12++) {
                  double C7 = (2 * lamb_12 + 1);
                  //
                  for (int lamb_3k = lamb_3kmin; lamb_3k <= lamb_3kmax;
                       lamb_3k++) {
                    // if (phase(lamb_3k + lamb_3 + lamb_k) != 1)
                    // continue;
                    double C8 =
                        Hat_vec[lamb_3k] * cg_int(lamb_3, lamb_k, lamb_3k);
                    if (C8 == 0.0)
                      continue;
                    // cout<<"C8 = "<<C8<<endl;
                    //
                    for (int lamb_4l = lamb_4lmin; lamb_4l <= lamb_4lmax;
                         lamb_4l++) {
                      if (phase(lamb_4l + lamb_4 + lamb_l) != 1)
                        continue;
                      int l3k_2 = lamb_3k * 2;
                      int l4l_2 = lamb_4l * 2;
                      int l12_2 = lamb_12 * 2;
                      if (Tri(l3k_2, l4l_2, l12_2) != 1)
                        continue;
                      int q3_min = std::abs(lamb_3k - l3p);
                      int q3_max = lamb_3k + l3p;
                      int q4_min = std::abs(lamb_4l - l3);
                      int q4_max = lamb_4l + l3;
                      double C9 =
                          Hat_vec[lamb_4l] * cg_int(lamb_4, lamb_l, lamb_4l);
                      C9 *= ninJ.cal(2 * lamb_3, 2 * lamb_4, 2, 2 * lamb_k,
                                     2 * lamb_l, 2 * lamb_2, 2 * lamb_3k,
                                     2 * lamb_4l, 2 * lamb_12);
                      // cout<<"C9 = "<<C9<<endl;
                      if (C9 == 0.0)
                        continue;
                      //
                      for (int q3 = q3_min; q3 <= q3_max; q3++) {
                        // if (phase(q3 + l3p + lamb_3k) != 1)
                        // continue;
                        double C10 = Hat_vec[q3] * cg_int(lamb_3k, q3, l3p);
                        if (C10 == 0.0)
                          continue;
                        //
                        for (int q4 = q4_min; q4 <= q4_max; q4++) {
                          if (phase(q4 + l3 + lamb_4l) != 1)
                            continue;
                          double C11 =
                              phase(q4) * Hat_vec[q4] * cg_int(lamb_4l, q4, l3);
                          if (C11 == 0.0)
                            continue;

                          double val = C1 * C2 * C3 * C4 * C5 * C6 * C7 * C8 *
                                       C9 * C10 * C11;

                          Ic1_t.lamb_1 = lamb_1;
                          Ic1_t.lamb_2 = lamb_2;
                          Ic1_t.lamb_3 = lamb_3;
                          Ic1_t.lamb_4 = lamb_4;
                          Ic1_t.lamb_i = lamb_i;
                          Ic1_t.lamb_j = lamb_j;
                          Ic1_t.lamb_k = lamb_k;
                          Ic1_t.lamb_l = lamb_l;
                          Ic1_t.lamb_12 = lamb_12;
                          Ic1_t.lamb_3k = lamb_3k;
                          Ic1_t.lamb_4l = lamb_4l;
                          Ic1_t.q_1 = q1;
                          Ic1_t.q_2 = q2;
                          Ic1_t.q_3 = q3;
                          Ic1_t.q_4 = q4;
                          Ic1_t.val = val;

                          Ic1_index[l_index].push_back(Ic1_t);
                          /*
                          Ic1_val[l_index].push_back(val);

                          Ic1_val2_t[0] = index + 0.0;
                          Ic1_val2_t[1] = C1;
                          Ic1_val2_t[2] = C2;
                          Ic1_val2_t[3] = C3;
                          Ic1_val2_t[4] = C4;
                          Ic1_val2_t[5] = C5;
                          Ic1_val2_t[6] = C6;
                          Ic1_val2_t[7] = C7;
                          Ic1_val2_t[8] = C8;
                          Ic1_val2_t[9] = C9;
                          Ic1_val2_t[10] = C10;
                          Ic1_val2_t[11] = C11;
                          Ic1_val2_t[12] = val;

                          Ic1_val2[l_index].push_back(Ic1_val2_t);
                          */
                          index++;
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  // cout << "Ic1 index all size = " << index << endl;

  std::ofstream file;
  /*file.open("data/Ic1_index.dat");
  for (int l = 0; l < Ic1_index.size(); l++) {
    file << "l : " << l << endl;
    // int l = 416;
    file << "i \tlamb_1 \tlamb_2 lamb_i \tlamb_j q1 \tq2 \tlamb_3 \tlamb_4 \t";
    file << "lamb_k \tlamb_l \tlamb_12 \tlamb_3k \tlamb_4l";
    file << "\t\tq3 \tq4 \t" << endl;
    for (int i = 0; i < Ic1_index[l].size(); i++) {
      file << i << "\t";
      file << Ic1_index[l][i].lamb_1 << "\t";
      file << Ic1_index[l][i].lamb_2 << "\t";
      file << Ic1_index[l][i].lamb_i << "\t";
      file << Ic1_index[l][i].lamb_j << "\t";
      file << Ic1_index[l][i].q_1 << "\t";
      file << Ic1_index[l][i].q_2 << "\t";
      file << Ic1_index[l][i].lamb_3 << "\t";
      file << Ic1_index[l][i].lamb_4 << "\t";
      file << Ic1_index[l][i].lamb_k << "\t";
      file << Ic1_index[l][i].lamb_l << "\t";
      file << Ic1_index[l][i].lamb_12 << "\t\t";
      file << Ic1_index[l][i].lamb_3k << "\t\t";
      file << Ic1_index[l][i].lamb_4l << "\t\t";
      file << Ic1_index[l][i].q_3 << "\t";
      file << Ic1_index[l][i].q_4 << "\t";
      file << Ic1_index[l][i].val << endl;
    }
  }
  file.close(); */
  this->Ic1_size = index;
  /*
  file.open("data/Ic1_val.dat");
  file
      << "i \tC1 \tC2 \tC3 \tC4 \tC5 \tC6 \tC7 \tC8 \tC9 \tC10 \tC11 \t\tC12 \t"
      << endl;
  int l = 0;
  for (int i = 0; i < Ic1_val2[l].size(); i++) {
    file << i << "\t";
    file << std::setprecision(3) << Ic1_val2[l][i][1] << "\t ";
    file << Ic1_val2[l][i][2] << "\t ";
    file << Ic1_val2[l][i][3] << "\t ";
    file << Ic1_val2[l][i][4] << "\t ";
    file << Ic1_val2[l][i][5] << "\t ";
    file << Ic1_val2[l][i][6] << "\t ";
    file << Ic1_val2[l][i][7] << "\t ";
    file << Ic1_val2[l][i][8] << "\t ";
    file << Ic1_val2[l][i][9] << "\t ";
    file << Ic1_val2[l][i][10] << "\t ";
    file << Ic1_val2[l][i][11] << "\t\t ";
    file << Ic1_val2[l][i][12] << endl;
  }
  file.close();
  *//*
  file.open("data/l_state.dat");
  for (int i = 0; i < l_state.size(); i++) {
    file << i << "\t" << l_state[i].l12p;
    file << "\t" << l_state[i].l12;
    file << "\t" << l_state[i].l3p;
    file << "\t" << l_state[i].l3 << endl;
  }
  file.close(); */

  // cout << "CG = " << cg.cal(2, 4, 4, 0, 0, 0) << "\t" << cg_int(0, 5, 5)
  //     << endl;
}

int Tpe_term::Hc1_cal(const int &l_index, const int &t0, const int &t1,
                      const int &t4, const Ic_struct &Ic1,
                      vector<Hc_struct> &Hc1) {

  int index = -1;

  int lamb_1 = Ic1.lamb_1;
  int lamb_2 = Ic1.lamb_2;
  int lamb_3 = Ic1.lamb_3;
  int lamb_4 = Ic1.lamb_4;
  int lamb_i = Ic1.lamb_i;
  int lamb_j = Ic1.lamb_j;
  int lamb_k = Ic1.lamb_k;
  int lamb_l = Ic1.lamb_l;
  int lamb_12 = Ic1.lamb_12;
  int lamb_3k = Ic1.lamb_3k;
  int lamb_4l = Ic1.lamb_4l;

  int q_1 = Ic1.q_1;
  int q_2 = Ic1.q_2;
  int q_3 = Ic1.q_3;
  int q_4 = Ic1.q_4;

  // cout << "Hc1_cal test 1 ?? " << endl;
  int lbar_min1 = std::abs(q_1 - q_2);
  int lbar_max1 = q_1 + q_2;
  int lbar_min2 = std::abs(q_3 - q_4);
  int lbar_max2 = q_3 + q_4;

  int lbar_minA = std::max(lbar_min1, lbar_min2);
  int lbar_maxA = std::min(lbar_max1, lbar_max2);

  if (lbar_minA > lbar_maxA)
    return index;

  int lbar_min3 = std::abs(lamb_2 - t0);
  int lbar_max3 = lamb_2 + t0;
  int lbar_min4 = std::abs(lamb_1 - t1);
  int lbar_max4 = lamb_1 + t1;

  int lbar_minB = std::max(lbar_min3, lbar_min4);
  int lbar_maxB = std::min(lbar_max3, lbar_max4);
  if (lbar_minB > lbar_maxB)
    return index;

  int lbar_min5 = std::abs(lamb_12 - t4);
  int lbar_max5 = lamb_12 + t4;
  int lbar_minC = std::max(lbar_minB, lbar_min5);
  int lbar_maxC = std::min(lbar_maxB, lbar_max5);
  if (lbar_minC > lbar_maxC)
    return index;

  int lbar_min = std::max(lbar_minA, lbar_minC);
  int lbar_max = std::min(lbar_maxA, lbar_maxC);
  if (lbar_min > lbar_max)
    return index;

  int l12p = l_state[l_index].l12p;
  int l12 = l_state[l_index].l12;
  int l3p = l_state[l_index].l3p;
  int l3 = l_state[l_index].l3;
  // cout << "Hc1_cal test 2 ?? " << endl;

  Hc_struct Hc1_state_t;
  for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
    // cout << lbar << endl;
    // cout << "Hc1_cal test 22 ?? " << endl;

    double H0 = sixJ.quick(2 * lamb_1, 2, 2 * lamb_2, 2 * t0, 2 * lbar, 2 * t1);
    // cout << "Hc1_cal test 22-1 ?? " << endl;
    if (H0 == 0.0)
      continue;
    // cout << "Hc1_cal test 22-2 ?? " << endl;
    H0 = H0 * sixJ.quick(2 * lamb_12, 2, 2 * lamb_2, 2 * t0, 2 * lbar, 2 * t4);
    // cout << "Hc1_cal test 22-3 ?? " << endl;
    if (H0 == 0.0)
      continue;
    // cout << "Hc1_cal test 22-4 ?? " << endl;
    H0 = H0 * ninJ.quick(2 * lamb_i, 2 * lamb_j, 2 * lamb_1, 2 * q_1, 2 * q_2,
                         2 * lbar, 2 * l12p, 2 * l12, 2 * t1);
    // cout << "Hc1_cal test 22-5 ?? " << endl;
    if (H0 == 0.0)
      continue;
    // cout << "Hc1_cal test 22-6 ?? " << endl;
    H0 = H0 * ninJ.quick(2 * lamb_3k, 2 * lamb_4l, 2 * lamb_12, 2 * q_3,
                         2 * q_4, 2 * lbar, 2 * l3p, 2 * l3, 2 * t4);
    // cout << "Hc1_cal test 22-7 ?? " << endl;
    if (H0 == 0.0)
      continue;
    H0 = H0 * phase(lbar);
    // cout << "Hc1_cal test 2-2 ?? " << endl;

    //
    for (int i_1 = 0; i_1 <= lbar; i_1++) {
      int i_2 = lbar - i_1;
      // cout << "Hc1_cal test 3 ?? " << endl;
      double H1 = BinoHat_cal(lbar, i_1);
      // cout << "Hc1_cal test 4 ?? " << endl;
      int lbar12_min1 = std::abs(i_1 - q_1);
      int lbar12_max1 = i_1 + q_1;
      int lbar12_min2 = std::abs(i_2 - q_2);
      int lbar12_max2 = i_2 + q_2;
      int lbar12_min = std::max(lbar12_min1, lbar12_min2);
      int lbar12_max = std::min(lbar12_max1, lbar12_max2);
      if (lbar12_min > lbar12_max)
        continue;
      for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
        // cout << "Hc1_cal test 33 ?? " << endl;
        double H2 = cg_int(i_1, lbar12, q_1) * cg_int(i_2, lbar12, q_2);
        // cout << "Hc1_cal test 44 ?? " << endl;
        if (H2 == 0.0)
          continue;
        // cout << "Hc1_cal test 55 ?? " << endl;
        H2 = H2 * sixJ.quick(2 * q_1, 2 * q_2, 2 * lbar, 2 * i_2, 2 * i_1,
                             2 * lbar12);
        // cout << "Hc1_cal test 66 ?? " << endl;
        if (H2 == 0.0)
          continue;
        // if(l == 6)cout<<" lbar12 : "<<lbar12<<endl;
        for (int i_3 = 0; i_3 <= lbar; i_3++) {
          int i_4 = lbar - i_3;
          // cout << "Hc1_cal test 5 ?? " << endl;
          double H3 = BinoHat_cal(lbar, i_3);
          // cout << "Hc1_cal test 6 ?? " << endl;
          int lbar3_min1 = std::abs(i_3 - q_3);
          int lbar3_max1 = i_3 + q_3;
          int lbar3_min2 = std::abs(i_4 - q_4);
          int lbar3_max2 = i_4 + q_4;
          int lbar3_min = std::max(lbar3_min1, lbar3_min2);
          int lbar3_max = std::min(lbar3_max1, lbar3_max2);
          if (lbar3_min > lbar3_max)
            continue;
          for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
            // cout << "Hc1_cal test 7 ?? " << endl;
            double H4 = cg_int(i_3, lbar3, q_3) * cg_int(i_4, lbar3, q_4);
            // cout << "Hc1_cal test 8 ?? " << endl;
            if (H4 == 0.0)
              continue;
            // cout << "Hc1_cal test 9 ?? " << endl;
            H4 = H4 * sixJ.quick(2 * q_3, 2 * q_4, 2 * lbar, 2 * i_4, 2 * i_3,
                                 2 * lbar3);
            // cout << "Hc1_cal test 10 ?? " << endl;
            if (H4 == 0.0)
              continue;
            // if(l == 6)cout<<" lbar3 : "<<lbar3<<endl;
            double val = H0 * H1 * H2 * H3 * H4;
            if (val == 0.0)
              continue;

            Hc1_state_t.lbar = lbar;
            Hc1_state_t.lbar_12 = lbar12;
            Hc1_state_t.lbar_3 = lbar3;
            Hc1_state_t.i_1 = i_1;
            Hc1_state_t.i_2 = i_2;
            Hc1_state_t.i_3 = i_3;
            Hc1_state_t.i_4 = i_4;
            Hc1_state_t.val = val;
            Hc1_state_t.H0 = H0;
            Hc1_state_t.H1 = H1;
            Hc1_state_t.H2 = H2;
            Hc1_state_t.H3 = H3;
            Hc1_state_t.H4 = H4;

            Hc1.push_back(Hc1_state_t);
            index++;
          }
        }
      }
    }
  }
  index++;
  // cout << "Finished Hc1_cal " << endl;
  return index;
}

void Tpe_term::Ic3_init() {
  /*
  for(int i=0; i<l_state.size(); i++)
    cout<<i<<"\t"<<l_state[i].l12p<<"\t"<<l_state[i].l12
      <<"\t"<<l_state[i].l3p<<"\t"<<l_state[i].l3<<endl;
  cout<<"$$$ \t "<<l_vec[3][2][0][5]<<endl;
  */

  int size_l = l_state.size();
  // double C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12;
  // double C_s1, C_s2, C_s3, C_s4;

  Ic3_index.resize(size_l);
  Ic3_val.resize(size_l);
  Ic3_val2.resize(size_l);
  // Ic_struct Ic3_t;
  vector<double> Ic3_val2_t;
  Ic3_val2_t.resize(17);

  int index = 0;
#pragma omp parallel for schedule(dynamic, 1)
  for (int l_index = 0; l_index < size_l; l_index++) {
    Ic_struct Ic3_t;

    int l12p = l_state[l_index].l12p;
    int l12 = l_state[l_index].l12;
    int l3p = l_state[l_index].l3p;
    int l3 = l_state[l_index].l3;
    index = 0;
    //
    for (int s_1 = 0; s_1 <= 2; s_1 = s_1 + 2) {
      double C_s1 = Hat_vec[s_1] * cg_int(1, 1, s_1);
      if (s_1 == 2)
        C_s1 = C_s1 * 0.5;
      //
      for (int s_2 = 0; s_2 <= 2; s_2 = s_2 + 2) {
        double C_s2 = Hat_vec[s_2] * cg_int(1, 1, s_2);
        if (s_2 == 2)
          C_s2 = C_s2 * 2.0 / 3.0;

        for (int lamb_1 = 0; lamb_1 <= s_1; lamb_1++) {
          int lamb_2 = s_1 - lamb_1;
          double C1 = BioHat[s_1][lamb_1];
          if (lamb_2 == 1) {
            C1 = C1 / (std::sqrt(3));
          }
          if (lamb_2 == 2) {
            C1 = C1 / 3.0;
          }
          // cout<<"C1 = "<<C1<<endl;
          //
          for (int lamb_i = 0; lamb_i <= lamb_1; lamb_i++) {
            int lamb_j = lamb_1 - lamb_i;
            int q1_min = std::abs(l12p - lamb_i);
            int q1_max = l12p + lamb_i;
            int q2_min = std::abs(l12 - lamb_j);
            int q2_max = l12 + lamb_j;
            double C2 = phase(lamb_j) * BioHat[lamb_1][lamb_i];
            //
            for (int q1 = q1_min; q1 <= q1_max; q1++) {
              // if (phase(q1 + lamb_i + l12p) != 1)
              // continue;
              double C3 = Hat_vec[q1] * cg_int(lamb_i, q1, l12p);
              if (C3 == 0.0)
                continue;
              // cout<<"C3 = "<<C3<<endl;
              //
              for (int q2 = q2_min; q2 <= q2_max; q2++) {
                // if (phase(q2 + lamb_j + l12) != 1)
                // continue;
                double C4 = phase(q2) * Hat_vec[q2] * cg_int(lamb_j, q2, l12);
                if (C4 == 0.0)
                  continue;
                // cout<<"C4 = "<<C4<<endl;
                //
                for (int lamb_3 = 0; lamb_3 <= s_2; lamb_3++) {
                  int lamb_4 = s_2 - lamb_3;
                  double C5 = phase(lamb_4) * BioHat[s_2][lamb_3];
                  //
                  for (int lamb_k = 0; lamb_k <= lamb_2; lamb_k++) {
                    int lamb_l = lamb_2 - lamb_k;
                    double C6 = phase(lamb_l) * BioHat[lamb_2][lamb_k];

                    int s_3min_1 = std::abs(1 - lamb_1);
                    int s_3min_2 = std::abs(1 - lamb_2);
                    int s_3min = std::max(s_3min_1, s_3min_2);
                    int s_3max = std::min((1 + lamb_1), (1 + lamb_2));
                    if (s_3min > s_3max)
                      continue;
                    int lamb_3kmin = std::abs(lamb_3 - lamb_k);
                    int lamb_3kmax = lamb_3 + lamb_k;
                    int lamb_4lmin = std::abs(lamb_4 - lamb_l);
                    int lamb_4lmax = lamb_4 + lamb_l;

                    // cout<<"C6 = "<<C6<<endl;
                    //
                    for (int s_3 = s_3min; s_3 <= s_3max; s_3++) {
                      double C_s3 =
                          (2 * s_3 + 1) * sixJ.quick(2, 2 * lamb_1, 2 * s_3,
                                                     2 * lamb_2, 2, 2 * s_1);
                      if (C_s3 == 0.0)
                        continue;
                      int s_4min =
                          std::max(std::abs(s_2 - lamb_2), std::abs(1 - s_3));
                      int s_4max = std::min((s_2 + lamb_2), (1 + s_3));
                      //
                      for (int s_4 = s_4min; s_4 <= s_4max; s_4++) {
                        double C_s4 = (2 * s_4 + 1) * phase(s_4) *
                                      sixJ.quick(2, 2 * s_2, 2, 2 * lamb_2,
                                                 2 * s_3, 2 * s_4);
                        if (C_s4 == 0.0)
                          continue;
                        //

                        for (int lamb_3k = lamb_3kmin; lamb_3k <= lamb_3kmax;
                             lamb_3k++) {
                          // if (phase(lamb_3k + lamb_3 + lamb_k) != 1)
                          // continue;
                          double C8 = Hat_vec[lamb_3k] *
                                      cg_int(lamb_3, lamb_k, lamb_3k);
                          if (C8 == 0.0)
                            continue;
                          // cout<<"C8 = "<<C8<<endl;
                          //
                          for (int lamb_4l = lamb_4lmin; lamb_4l <= lamb_4lmax;
                               lamb_4l++) {
                            if (phase(lamb_4l + lamb_4 + lamb_l) != 1)
                              continue;

                            int q3_min = std::abs(lamb_3k - l3p);
                            int q3_max = lamb_3k + l3p;
                            int q4_min = std::abs(lamb_4l - l3);
                            int q4_max = lamb_4l + l3;
                            double C9 = Hat_vec[lamb_4l] *
                                        cg_int(lamb_4, lamb_l, lamb_4l);
                            C9 *= ninJ.cal(2 * lamb_3, 2 * lamb_4, 2 * s_2,
                                           2 * lamb_k, 2 * lamb_l, 2 * lamb_2,
                                           2 * lamb_3k, 2 * lamb_4l, 2 * s_4);
                            // cout<<"C9 = "<<C9<<endl;
                            if (C9 == 0.0)
                              continue;
                            //
                            for (int q3 = q3_min; q3 <= q3_max; q3++) {
                              // if (phase(q3 + l3p + lamb_3k) != 1)
                              // continue;
                              double C10 =
                                  Hat_vec[q3] * cg_int(lamb_3k, q3, l3p);
                              if (C10 == 0.0)
                                continue;
                              //
                              for (int q4 = q4_min; q4 <= q4_max; q4++) {
                                if (phase(q4 + l3 + lamb_4l) != 1)
                                  continue;
                                double C11 = phase(q4) * Hat_vec[q4] *
                                             cg_int(lamb_4l, q4, l3);
                                if (C11 == 0.0)
                                  continue;

                                double val = C1 * C2 * C3 * C4 * C5 * C6 * C8 *
                                             C9 * C10 * C11 * C_s1 * C_s2 *
                                             C_s3 * C_s4;

                                Ic3_t.lamb_1 = lamb_1;
                                Ic3_t.lamb_2 = lamb_2;
                                Ic3_t.lamb_3 = lamb_3;
                                Ic3_t.lamb_4 = lamb_4;
                                Ic3_t.lamb_i = lamb_i;
                                Ic3_t.lamb_j = lamb_j;
                                Ic3_t.lamb_k = lamb_k;
                                Ic3_t.lamb_l = lamb_l;
                                // Ic3_t.lamb_12 = lamb_12;
                                Ic3_t.lamb_3k = lamb_3k;
                                Ic3_t.lamb_4l = lamb_4l;
                                Ic3_t.q_1 = q1;
                                Ic3_t.q_2 = q2;
                                Ic3_t.q_3 = q3;
                                Ic3_t.q_4 = q4;
                                Ic3_t.val = val;
                                Ic3_t.s_1 = s_1;
                                Ic3_t.s_2 = s_2;
                                Ic3_t.s_3 = s_3;
                                Ic3_t.s_4 = s_4;

                                Ic3_index[l_index].push_back(Ic3_t);
                                /*
                                Ic3_val[l_index].push_back(val);

                                Ic3_val2_t[0] = index + 0.0;
                                Ic3_val2_t[1] = C1;
                                Ic3_val2_t[2] = C2;
                                Ic3_val2_t[3] = C3;
                                Ic3_val2_t[4] = C4;
                                Ic3_val2_t[5] = C5;
                                Ic3_val2_t[6] = C6;
                                Ic3_val2_t[7] = C7;
                                Ic3_val2_t[8] = C8;
                                Ic3_val2_t[9] = C9;
                                Ic3_val2_t[10] = C10;
                                Ic3_val2_t[11] = C11;
                                Ic3_val2_t[12] = C_s1;
                                Ic3_val2_t[13] = C_s2;
                                Ic3_val2_t[14] = C_s3;
                                Ic3_val2_t[15] = C_s4;
                                Ic3_val2_t[16] = val;

                                Ic3_val2[l_index].push_back(Ic3_val2_t);
                                */
                                index++;
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  this->Ic3_size = index;
  /*std::ofstream file;
  file.open("data/Ic3_index.dat");
  for (int l = 0; l < Ic3_index.size(); l++) {
    file << "l : " << l << endl;
    // int l = 416;
    file << "i \ts_1 \ts_2 \tlamb_1 \tlamb_2 lamb_i \tlamb_j q1 \tq2 \tlamb_3 "
            "\tlamb_4 \t";
    file << "lamb_k \tlamb_l \ts_3 \ts_4 \tlamb_3k \tlamb_4l";
    file << "\t\tq3 \tq4 \t" << endl;
    for (int i = 0; i < Ic3_index[l].size(); i++) {
      file << i << "\t";
      file << Ic3_index[l][i].s_1 << "\t";
      file << Ic3_index[l][i].s_2 << "\t";
      file << Ic3_index[l][i].lamb_1 << "\t";
      file << Ic3_index[l][i].lamb_2 << "\t";
      file << Ic3_index[l][i].lamb_i << "\t";
      file << Ic3_index[l][i].lamb_j << "\t";
      file << Ic3_index[l][i].q_1 << "\t";
      file << Ic3_index[l][i].q_2 << "\t";
      file << Ic3_index[l][i].lamb_3 << "\t";
      file << Ic3_index[l][i].lamb_4 << "\t";
      file << Ic3_index[l][i].lamb_k << "\t";
      file << Ic3_index[l][i].lamb_l << "\t";
      //      file << Ic3_index[l][i].lamb_12 << "\t\t";
      file << Ic3_index[l][i].s_3 << "\t";
      file << Ic3_index[l][i].s_4 << "\t";
      file << Ic3_index[l][i].lamb_3k << "\t\t";
      file << Ic3_index[l][i].lamb_4l << "\t\t";
      file << Ic3_index[l][i].q_3 << "\t";
      file << Ic3_index[l][i].q_4 << "\t\t";
      file << Ic3_index[l][i].val << endl;
    }
  }
  file.close(); */

  /*
  file.open("data/Ic3_val.dat");
  file << "i \tC_s1 \tC_s2 \tC1 \tC2 \tC3 \tC4 \tC5 \tC6 \tC_s3 \tC_s4 \tC8 "
          "\tC9 \tC10 \tC11 \t\t val"
       << endl;
  int l = 3;
  for (int i = 0; i < Ic3_val2[l].size(); i++) {
    file << i << "\t";
    file << std::setprecision(3);
    file << Ic3_val2[l][i][12] << "\t ";
    file << Ic3_val2[l][i][13] << "\t ";
    file << Ic3_val2[l][i][1] << "\t ";
    file << Ic3_val2[l][i][2] << "\t ";
    file << Ic3_val2[l][i][3] << "\t ";
    file << Ic3_val2[l][i][4] << "\t ";
    file << Ic3_val2[l][i][5] << "\t ";
    file << Ic3_val2[l][i][6] << "\t ";
    // file << Ic3_val2[l][i][7] << "\t ";
    file << Ic3_val2[l][i][14] << "\t ";
    file << Ic3_val2[l][i][15] << "\t";
    file << Ic3_val2[l][i][8] << "\t ";
    file << Ic3_val2[l][i][9] << "\t ";
    file << Ic3_val2[l][i][10] << "\t ";
    file << Ic3_val2[l][i][11] << "\t\t ";
    file << Ic3_val2[l][i][16] << endl;
  }
  file.close();
  */
  // cout << "CG = " << cg.cal(2, 4, 4, 0, 0, 0) << "\t" << cg_int(0, 5, 5)
  //     << endl;
}

int Tpe_term::Hc3_cal(const int &l_index, const int &t0, const int &t1,
                      const int &t4, const Ic_struct &Ic3,
                      vector<Hc_struct> &Hc3) {
  int index = -1;
  // cout<<"good?"<<endl;
  // Hc1
  int q_1 = Ic3.q_1;
  int q_2 = Ic3.q_2;
  int q_3 = Ic3.q_3;
  int q_4 = Ic3.q_4;

  int lbar_min1 = std::abs(q_1 - q_2);
  int lbar_max1 = q_1 + q_2;
  int lbar_min2 = std::abs(q_3 - q_4);
  int lbar_max2 = q_3 + q_4;

  int lbar_minA = std::max(lbar_min1, lbar_min2);
  int lbar_maxA = std::min(lbar_max1, lbar_max2);

  if (lbar_minA > lbar_maxA)
    return index;

  int s_3 = Ic3.s_3;
  int s_4 = Ic3.s_4;
  int lamb_1 = Ic3.lamb_1;
  int lbar_min3 = std::abs(s_3 - t0);
  int lbar_max3 = s_3 + t0;
  int lbar_min4 = std::abs(lamb_1 - t1);
  int lbar_max4 = lamb_1 + t1;
  int lbar_min5 = std::abs(s_4 - t4);
  int lbar_max5 = s_4 + t4;

  int lbar_minB = std::max(lbar_min3, lbar_min4);
  int lbar_maxB = std::min(lbar_max3, lbar_max4);
  if (lbar_minB > lbar_maxB)
    return index;

  int lbar_minC = std::max(lbar_minB, lbar_min5);
  int lbar_maxC = std::min(lbar_maxB, lbar_max5);
  if (lbar_minC > lbar_maxC)
    return index;

  int lbar_min = std::max(lbar_minA, lbar_minC);
  int lbar_max = std::min(lbar_maxA, lbar_maxC);
  if (lbar_min > lbar_max)
    return index;

  int lamb_2 = Ic3.lamb_2;
  int lamb_3 = Ic3.lamb_3;
  int lamb_4 = Ic3.lamb_4;
  int lamb_i = Ic3.lamb_i;
  int lamb_j = Ic3.lamb_j;
  int lamb_k = Ic3.lamb_k;
  int lamb_l = Ic3.lamb_l;
  // int lamb_12 = Ic1_index[l][i].lamb_12;
  int lamb_3k = Ic3.lamb_3k;
  int lamb_4l = Ic3.lamb_4l;

  int l12p = l_state[l_index].l12p;
  int l12 = l_state[l_index].l12;
  int l3p = l_state[l_index].l3p;
  int l3 = l_state[l_index].l3;

  Hc_struct Hc3_state_t;

  for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
    // cout<<lbar<<endl;
    double H0 = sixJ.quick(2 * lamb_1, 2, 2 * s_3, 2 * t0, 2 * lbar, 2 * t1);
    if (H0 == 0.0)
      continue;
    H0 = H0 * sixJ.quick(2 * s_4, 2, 2 * s_3, 2 * t0, 2 * lbar, 2 * t4);
    if (H0 == 0.0)
      continue;
    H0 = H0 * ninJ.quick(2 * lamb_i, 2 * lamb_j, 2 * lamb_1, 2 * q_1, 2 * q_2,
                         2 * lbar, 2 * l12p, 2 * l12, 2 * t1);
    if (H0 == 0.0)
      continue;
    H0 = H0 * ninJ.cal(2 * lamb_3k, 2 * lamb_4l, 2 * s_4, 2 * q_3, 2 * q_4,
                       2 * lbar, 2 * l3p, 2 * l3, 2 * t4);
    if (H0 == 0.0)
      continue;
    H0 = H0 * phase(lbar);
    for (int i_1 = 0; i_1 <= lbar; i_1++) {
      int i_2 = lbar - i_1;
      double H1 = BinoHat_cal(lbar, i_1);
      int lbar12_min1 = std::abs(i_1 - q_1);
      int lbar12_max1 = i_1 + q_1;
      int lbar12_min2 = std::abs(i_2 - q_2);
      int lbar12_max2 = i_2 + q_2;
      int lbar12_min = std::max(lbar12_min1, lbar12_min2);
      int lbar12_max = std::min(lbar12_max1, lbar12_max2);
      if (lbar12_min > lbar12_max)
        continue;
      for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
        double H2 = cg_int(i_1, lbar12, q_1) * cg_int(i_2, lbar12, q_2);
        if (H2 == 0.0)
          continue;
        H2 = H2 * sixJ.quick(2 * q_1, 2 * q_2, 2 * lbar, 2 * i_2, 2 * i_1,
                             2 * lbar12);
        if (H2 == 0.0)
          continue;
        // if(l == 6)cout<<" lbar12 : "<<lbar12<<endl;
        for (int i_3 = 0; i_3 <= lbar; i_3++) {
          int i_4 = lbar - i_3;
          double H3 = BinoHat_cal(lbar, i_3);
          int lbar3_min1 = std::abs(i_3 - q_3);
          int lbar3_max1 = i_3 + q_3;
          int lbar3_min2 = std::abs(i_4 - q_4);
          int lbar3_max2 = i_4 + q_4;
          int lbar3_min = std::max(lbar3_min1, lbar3_min2);
          int lbar3_max = std::min(lbar3_max1, lbar3_max2);
          if (lbar3_min > lbar3_max)
            continue;
          for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
            double H4 = cg_int(i_3, lbar3, q_3) * cg_int(i_4, lbar3, q_4);
            if (H4 == 0.0)
              continue;
            H4 = H4 * sixJ.quick(2 * q_3, 2 * q_4, 2 * lbar, 2 * i_4, 2 * i_3,
                                 2 * lbar3);
            if (H4 == 0.0)
              continue;
            // if(l == 6)cout<<" lbar3 : "<<lbar3<<endl;
            double val = H0 * H1 * H2 * H3 * H4;

            Hc3_state_t.lbar = lbar;
            Hc3_state_t.lbar_12 = lbar12;
            Hc3_state_t.lbar_3 = lbar3;
            Hc3_state_t.i_1 = i_1;
            Hc3_state_t.i_2 = i_2;
            Hc3_state_t.i_3 = i_3;
            Hc3_state_t.i_4 = i_4;
            Hc3_state_t.val = val;
            Hc3_state_t.H0 = H0;
            Hc3_state_t.H1 = H1;
            Hc3_state_t.H2 = H2;
            Hc3_state_t.H3 = H3;
            Hc3_state_t.H4 = H4;

            Hc3.push_back(Hc3_state_t);
            index++;
          }
        }
      }
    }
  }
  index++;
  return index;
}

void Tpe_term::Ic4_init() {
  /*
  for(int i=0; i<l_state.size(); i++)
    cout<<i<<"\t"<<l_state[i].l12p<<"\t"<<l_state[i].l12
      <<"\t"<<l_state[i].l3p<<"\t"<<l_state[i].l3<<endl;
  cout<<"$$$ \t "<<l_vec[3][2][0][5]<<endl;
  */

  int size_l = l_state.size();
  // double C1, C2, C3, C4, C5, C6, C7, C8, C9, C10, C11, C12;
  // double C_s1, C_s2, C_s3, C_s4;
  Ic4_index.resize(3); // s_0 = 0,1,2
  Ic4_val.resize(3);
  Ic4_val2.resize(3);
  for (int i = 0; i < 3; i++) {
    Ic4_index[i].resize(size_l);
    Ic4_val[i].resize(size_l);
    Ic4_val2[i].resize(size_l);
  }

  // Ic_struct Ic4_t;
  vector<double> Ic4_val2_t;
  Ic4_val2_t.resize(17);
  // cout<<"Good ?"<<endl;
  int index = 0;
  //#pragma omp parallel for
  for (int s_0 = 0; s_0 <= 2; s_0++) {
#pragma omp parallel for schedule(dynamic, 1)
    for (int l_index = 0; l_index < size_l; l_index++) {
      Ic_struct Ic4_t;

      int l12p = l_state[l_index].l12p;
      int l12 = l_state[l_index].l12;
      int l3p = l_state[l_index].l3p;
      int l3 = l_state[l_index].l3;
      index = 0;
      //
      for (int s_1 = 0; s_1 <= 2; s_1 = s_1 + 2) {
        double C_s1 = Hat_vec[s_1] * cg_int(1, 1, s_1);
        if (s_1 == 2)
          C_s1 = C_s1 * 0.5;
        C_s1 = C_s1 * sixJ.quick(2 * s_0, 2 * s_1, 2, 2, 2, 2);
        if (C_s1 == 0.0)
          continue;
        //
        for (int s_2 = 0; s_2 <= 2; s_2 = s_2 + 2) {
          double C_s2 = Hat_vec[s_2] * cg_int(1, 1, s_2);
          if (s_2 == 2)
            C_s2 = C_s2 * 2.0 / 3.0;

          for (int lamb_1 = 0; lamb_1 <= s_1; lamb_1++) {
            int lamb_2 = s_1 - lamb_1;
            double C1 = BioHat[s_1][lamb_1];
            if (lamb_2 == 1) {
              C1 = C1 / (std::sqrt(3));
            }
            if (lamb_2 == 2) {
              C1 = C1 / 3.0;
            }
            // cout<<"C1 = "<<C1<<endl;
            //
            for (int lamb_i = 0; lamb_i <= lamb_1; lamb_i++) {
              int lamb_j = lamb_1 - lamb_i;
              int q1_min = std::abs(l12p - lamb_i);
              int q1_max = l12p + lamb_i;
              int q2_min = std::abs(l12 - lamb_j);
              int q2_max = l12 + lamb_j;
              double C2 = phase(lamb_j) * BioHat[lamb_1][lamb_i];
              //
              for (int q1 = q1_min; q1 <= q1_max; q1++) {
                // if (phase(q1 + lamb_i + l12p) != 1)
                // continue;
                double C3 = Hat_vec[q1] * cg_int(lamb_i, q1, l12p);
                if (C3 == 0.0)
                  continue;
                // cout<<"C3 = "<<C3<<endl;
                //
                for (int q2 = q2_min; q2 <= q2_max; q2++) {
                  // if (phase(q2 + lamb_j + l12) != 1)
                  // continue;
                  double C4 = phase(q2) * Hat_vec[q2] * cg_int(lamb_j, q2, l12);
                  if (C4 == 0.0)
                    continue;
                  // cout<<"C4 = "<<C4<<endl;
                  //
                  for (int lamb_3 = 0; lamb_3 <= s_2; lamb_3++) {
                    int lamb_4 = s_2 - lamb_3;
                    double C5 = phase(lamb_4) * BioHat[s_2][lamb_3];
                    //
                    for (int lamb_k = 0; lamb_k <= lamb_2; lamb_k++) {
                      int lamb_l = lamb_2 - lamb_k;
                      double C6 = phase(lamb_l) * BioHat[lamb_2][lamb_k];

                      int s_3min_1 = std::abs(s_0 - lamb_1);
                      int s_3min_2 = std::abs(1 - lamb_2);
                      int s_3min = std::max(s_3min_1, s_3min_2);
                      int s_3max = std::min((s_0 + lamb_1), (1 + lamb_2));
                      if (s_3min > s_3max)
                        continue;
                      int lamb_3kmin = std::abs(lamb_3 - lamb_k);
                      int lamb_3kmax = lamb_3 + lamb_k;
                      int lamb_4lmin = std::abs(lamb_4 - lamb_l);
                      int lamb_4lmax = lamb_4 + lamb_l;

                      // cout<<"C6 = "<<C6<<endl;
                      //
                      for (int s_3 = s_3min; s_3 <= s_3max; s_3++) {
                        double C_s3 = (2 * s_3 + 1) *
                                      sixJ.quick(2 * s_0, 2 * lamb_1, 2 * s_3,
                                                 2 * lamb_2, 2, 2 * s_1);
                        if (C_s3 == 0.0)
                          continue;
                        int s_4min =
                            std::max(std::abs(s_2 - lamb_2), std::abs(1 - s_3));
                        int s_4max = std::min((s_2 + lamb_2), (1 + s_3));
                        //
                        for (int s_4 = s_4min; s_4 <= s_4max; s_4++) {
                          double C_s4 = (2 * s_4 + 1) * phase(s_4) *
                                        sixJ.quick(2, 2 * s_2, 2, 2 * lamb_2,
                                                   2 * s_3, 2 * s_4);
                          if (C_s4 == 0.0)
                            continue;
                          //

                          for (int lamb_3k = lamb_3kmin; lamb_3k <= lamb_3kmax;
                               lamb_3k++) {
                            // if (phase(lamb_3k + lamb_3 + lamb_k) != 1)
                            // continue;
                            double C8 = Hat_vec[lamb_3k] *
                                        cg_int(lamb_3, lamb_k, lamb_3k);
                            if (C8 == 0.0)
                              continue;
                            // cout<<"C8 = "<<C8<<endl;
                            //
                            for (int lamb_4l = lamb_4lmin;
                                 lamb_4l <= lamb_4lmax; lamb_4l++) {
                              if (phase(lamb_4l + lamb_4 + lamb_l) != 1)
                                continue;

                              int q3_min = std::abs(lamb_3k - l3p);
                              int q3_max = lamb_3k + l3p;
                              int q4_min = std::abs(lamb_4l - l3);
                              int q4_max = lamb_4l + l3;
                              double C9 = Hat_vec[lamb_4l] *
                                          cg_int(lamb_4, lamb_l, lamb_4l);
                              C9 *= ninJ.cal(2 * lamb_3, 2 * lamb_4, 2 * s_2,
                                             2 * lamb_k, 2 * lamb_l, 2 * lamb_2,
                                             2 * lamb_3k, 2 * lamb_4l, 2 * s_4);
                              // cout<<"C9 = "<<C9<<endl;
                              if (C9 == 0.0)
                                continue;
                              //
                              for (int q3 = q3_min; q3 <= q3_max; q3++) {
                                // if (phase(q3 + l3p + lamb_3k) != 1)
                                // continue;
                                double C10 =
                                    Hat_vec[q3] * cg_int(lamb_3k, q3, l3p);
                                if (C10 == 0.0)
                                  continue;
                                //
                                for (int q4 = q4_min; q4 <= q4_max; q4++) {
                                  if (phase(q4 + l3 + lamb_4l) != 1)
                                    continue;
                                  double C11 = phase(q4) * Hat_vec[q4] *
                                               cg_int(lamb_4l, q4, l3);
                                  if (C11 == 0.0)
                                    continue;

                                  double val = C1 * C2 * C3 * C4 * C5 * C6 *
                                               C8 * C9 * C10 * C11 * C_s1 *
                                               C_s2 * C_s3 * C_s4;

                                  Ic4_t.lamb_1 = lamb_1;
                                  Ic4_t.lamb_2 = lamb_2;
                                  Ic4_t.lamb_3 = lamb_3;
                                  Ic4_t.lamb_4 = lamb_4;
                                  Ic4_t.lamb_i = lamb_i;
                                  Ic4_t.lamb_j = lamb_j;
                                  Ic4_t.lamb_k = lamb_k;
                                  Ic4_t.lamb_l = lamb_l;
                                  // Ic4_t.lamb_12 = lamb_12;
                                  Ic4_t.lamb_3k = lamb_3k;
                                  Ic4_t.lamb_4l = lamb_4l;
                                  Ic4_t.q_1 = q1;
                                  Ic4_t.q_2 = q2;
                                  Ic4_t.q_3 = q3;
                                  Ic4_t.q_4 = q4;
                                  Ic4_t.val = val;
                                  Ic4_t.s_1 = s_1;
                                  Ic4_t.s_2 = s_2;
                                  Ic4_t.s_3 = s_3;
                                  Ic4_t.s_4 = s_4;

                                  Ic4_index[s_0][l_index].push_back(Ic4_t);
                                  /*
                                  Ic4_val[s_0][l_index].push_back(val);

                                  Ic4_val2_t[0] = index + 0.0;
                                  Ic4_val2_t[1] = C1;
                                  Ic4_val2_t[2] = C2;
                                  Ic4_val2_t[3] = C3;
                                  Ic4_val2_t[4] = C4;
                                  Ic4_val2_t[5] = C5;
                                  Ic4_val2_t[6] = C6;
                                  Ic4_val2_t[7] = C7;
                                  Ic4_val2_t[8] = C8;
                                  Ic4_val2_t[9] = C9;
                                  Ic4_val2_t[10] = C10;
                                  Ic4_val2_t[11] = C11;
                                  Ic4_val2_t[12] = C_s1;
                                  Ic4_val2_t[13] = C_s2;
                                  Ic4_val2_t[14] = C_s3;
                                  Ic4_val2_t[15] = C_s4;
                                  Ic4_val2_t[16] = val;

                                  Ic4_val2[s_0][l_index].push_back(Ic4_val2_t);
                                  */
                                  index++;
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  // cout<<"Good 2@2 ?"<<endl;
  /*std::ofstream file;
  file.open("data/Ic4_index.dat");
  for (int s_0 = 0; s_0 <= 2; s_0++) {
    for (int l = 0; l < Ic4_index[s_0].size(); l++) {
      file << "l : " << l << "\t s_0 : " << s_0 << endl;
      // int l = 416;
      file << "i \ts_1 \ts_2 \tlamb_1 \tlamb_2 lamb_i \tlamb_j q1 \tq2 "
              "\tlamb_3 "
              "\tlamb_4 \t";
      file << "lamb_k \tlamb_l \ts_3 \ts_4 \tlamb_3k \tlamb_4l";
      file << "\t\tq3 \tq4 \t" << endl;
      for (int i = 0; i < Ic4_index[s_0][l].size(); i++) {
        file << i << "\t";
        file << Ic4_index[s_0][l][i].s_1 << "\t";
        file << Ic4_index[s_0][l][i].s_2 << "\t";
        file << Ic4_index[s_0][l][i].lamb_1 << "\t";
        file << Ic4_index[s_0][l][i].lamb_2 << "\t";
        file << Ic4_index[s_0][l][i].lamb_i << "\t";
        file << Ic4_index[s_0][l][i].lamb_j << "\t";
        file << Ic4_index[s_0][l][i].q_1 << "\t";
        file << Ic4_index[s_0][l][i].q_2 << "\t";
        file << Ic4_index[s_0][l][i].lamb_3 << "\t";
        file << Ic4_index[s_0][l][i].lamb_4 << "\t";
        file << Ic4_index[s_0][l][i].lamb_k << "\t";
        file << Ic4_index[s_0][l][i].lamb_l << "\t";
        //      file << Ic3_index[l][i].lamb_12 << "\t\t";
        file << Ic4_index[s_0][l][i].s_3 << "\t";
        file << Ic4_index[s_0][l][i].s_4 << "\t";
        file << Ic4_index[s_0][l][i].lamb_3k << "\t\t";
        file << Ic4_index[s_0][l][i].lamb_4l << "\t\t";
        file << Ic4_index[s_0][l][i].q_3 << "\t";
        file << Ic4_index[s_0][l][i].q_4 << "\t\t";
        file << Ic4_index[s_0][l][i].val << endl;
      }
    }
  }
  file.close(); */

  // Find lbar_max

  this->Ic4_size = index;

  /*
  file.open("data/Ic4_val.dat");
  file << "i \tC_s1 \tC_s2 \tC1 \tC2 \tC3 \tC4 \tC5 \tC6 \tC_s3 \tC_s4 \tC8 "
          "\tC9 \tC10 \tC11 \t\t val"
       << endl;
  int l = 3;
  int s_0 = 0;
  for (int i = 0; i < Ic4_val2[s_0][l].size(); i++) {
    file << i << "\t";
    file << std::setprecision(3);
    file << Ic4_val2[s_0][l][i][12] << "\t ";
    file << Ic4_val2[s_0][l][i][13] << "\t ";
    file << Ic4_val2[s_0][l][i][1] << "\t ";
    file << Ic4_val2[s_0][l][i][2] << "\t ";
    file << Ic4_val2[s_0][l][i][3] << "\t ";
    file << Ic4_val2[s_0][l][i][4] << "\t ";
    file << Ic4_val2[s_0][l][i][5] << "\t ";
    file << Ic4_val2[s_0][l][i][6] << "\t ";
    // file << Ic3_val2[l][i][7] << "\t ";
    file << Ic4_val2[s_0][l][i][14] << "\t ";
    file << Ic4_val2[s_0][l][i][15] << "\t";
    file << Ic4_val2[s_0][l][i][8] << "\t ";
    file << Ic4_val2[s_0][l][i][9] << "\t ";
    file << Ic4_val2[s_0][l][i][10] << "\t ";
    file << Ic4_val2[s_0][l][i][11] << "\t\t ";
    file << Ic4_val2[s_0][l][i][16] << endl;
  }
  file.close();
  */
  // cout << "CG = " << cg.cal(2, 4, 4, 0, 0, 0) << "\t" << cg_int(0, 5, 5)
  //     << endl;
}

int Tpe_term::Hc4_cal(const int &l_index, const int &t0, const int &t1,
                      const int &t4, const int &s_0, const Ic_struct &Ic4,
                      vector<Hc_struct> &Hc4) {

  int index = -1;

  int q_1 = Ic4.q_1;
  int q_2 = Ic4.q_2;
  int q_3 = Ic4.q_3;
  int q_4 = Ic4.q_4;

  int lbar_min1 = std::abs(q_1 - q_2);
  int lbar_max1 = q_1 + q_2;
  int lbar_min2 = std::abs(q_3 - q_4);
  int lbar_max2 = q_3 + q_4;

  int lbar_minA = std::max(lbar_min1, lbar_min2);
  int lbar_maxA = std::min(lbar_max1, lbar_max2);
  if (lbar_minA > lbar_maxA)
    return index;

  int s_3 = Ic4.s_3;
  int s_4 = Ic4.s_4;
  int lamb_1 = Ic4.lamb_1;
  int lbar_min3 = std::abs(s_3 - t0);
  int lbar_max3 = s_3 + t0;
  int lbar_min4 = std::abs(lamb_1 - t1);
  int lbar_max4 = lamb_1 + t1;
  int lbar_min5 = std::abs(s_4 - t4);
  int lbar_max5 = s_4 + t4;

  int lbar_minB = std::max(lbar_min3, lbar_min4);
  int lbar_minC = std::max(lbar_minB, lbar_min5);
  int lbar_maxB = std::min(lbar_max3, lbar_max4);
  int lbar_maxC = std::min(lbar_maxB, lbar_max5);

  int lbar_min = std::max(lbar_minA, lbar_minC);
  int lbar_max = std::min(lbar_maxA, lbar_maxC);
  if (lbar_min > lbar_max)
    return index;

  int lamb_2 = Ic4.lamb_2;
  int lamb_3 = Ic4.lamb_3;
  int lamb_4 = Ic4.lamb_4;
  int lamb_i = Ic4.lamb_i;
  int lamb_j = Ic4.lamb_j;
  int lamb_k = Ic4.lamb_k;
  int lamb_l = Ic4.lamb_l;
  // int lamb_12 = Ic1_index[l][i].lamb_12;
  int lamb_3k = Ic4.lamb_3k;
  int lamb_4l = Ic4.lamb_4l;

  int l12p = l_state[l_index].l12p;
  int l12 = l_state[l_index].l12;
  int l3p = l_state[l_index].l3p;
  int l3 = l_state[l_index].l3;

  Hc_struct Hc4_state_t;
  for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
    // cout<<lbar<<endl;
    double H0 =
        sixJ.quick(2 * lamb_1, 2 * s_0, 2 * s_3, 2 * t0, 2 * lbar, 2 * t1);
    if (H0 == 0.0)
      continue;
    H0 = H0 * sixJ.quick(2 * s_4, 2, 2 * s_3, 2 * t0, 2 * lbar, 2 * t4);
    if (H0 == 0.0)
      continue;
    H0 = H0 * ninJ.cal(2 * lamb_i, 2 * lamb_j, 2 * lamb_1, 2 * q_1, 2 * q_2,
                       2 * lbar, 2 * l12p, 2 * l12, 2 * t1);
    if (H0 == 0.0)
      continue;
    H0 = H0 * ninJ.cal(2 * lamb_3k, 2 * lamb_4l, 2 * s_4, 2 * q_3, 2 * q_4,
                       2 * lbar, 2 * l3p, 2 * l3, 2 * t4);
    if (H0 == 0.0)
      continue;
    H0 = H0 * phase(lbar);
    /*if (l == 0 &&i == 13)
      cout << " l = " << l << ", lbar: " << lbar << "\t t : " << t
           << "\t H0 : " << H0 << endl;
           */
    for (int i_1 = 0; i_1 <= lbar; i_1++) {
      int i_2 = lbar - i_1;
      double H1 = BinoHat_cal(lbar, i_1);
      int lbar12_min1 = std::abs(i_1 - q_1);
      int lbar12_max1 = i_1 + q_1;
      int lbar12_min2 = std::abs(i_2 - q_2);
      int lbar12_max2 = i_2 + q_2;
      int lbar12_min = std::max(lbar12_min1, lbar12_min2);
      int lbar12_max = std::min(lbar12_max1, lbar12_max2);
      if (lbar12_min > lbar12_max)
        continue;
      for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
        double H2 = cg_int(i_1, lbar12, q_1) * cg_int(i_2, lbar12, q_2);
        if (H2 == 0.0)
          continue;
        H2 = H2 * sixJ.quick(2 * q_1, 2 * q_2, 2 * lbar, 2 * i_2, 2 * i_1,
                             2 * lbar12);
        if (H2 == 0.0)
          continue;
        // if(l == 6)cout<<" lbar12 : "<<lbar12<<endl;
        for (int i_3 = 0; i_3 <= lbar; i_3++) {
          int i_4 = lbar - i_3;
          double H3 = BinoHat_cal(lbar, i_3);
          int lbar3_min1 = std::abs(i_3 - q_3);
          int lbar3_max1 = i_3 + q_3;
          int lbar3_min2 = std::abs(i_4 - q_4);
          int lbar3_max2 = i_4 + q_4;
          int lbar3_min = std::max(lbar3_min1, lbar3_min2);
          int lbar3_max = std::min(lbar3_max1, lbar3_max2);
          if (lbar3_min > lbar3_max)
            continue;
          for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
            double H4 = cg_int(i_3, lbar3, q_3) * cg_int(i_4, lbar3, q_4);
            if (H4 == 0.0)
              continue;
            H4 = H4 * sixJ.quick(2 * q_3, 2 * q_4, 2 * lbar, 2 * i_4, 2 * i_3,
                                 2 * lbar3);
            if (H4 == 0.0)
              continue;
            // if(l == 6)cout<<" lbar3 : "<<lbar3<<endl;
            double val = H0 * H1 * H2 * H3 * H4;

            Hc4_state_t.lbar = lbar;
            Hc4_state_t.lbar_12 = lbar12;
            Hc4_state_t.lbar_3 = lbar3;
            Hc4_state_t.i_1 = i_1;
            Hc4_state_t.i_2 = i_2;
            Hc4_state_t.i_3 = i_3;
            Hc4_state_t.i_4 = i_4;
            Hc4_state_t.val = val;
            Hc4_state_t.H0 = H0;
            Hc4_state_t.H1 = H1;
            Hc4_state_t.H2 = H2;
            Hc4_state_t.H3 = H3;
            Hc4_state_t.H4 = H4;

            Hc4.push_back(Hc4_state_t);
            index++;
          }
        }
      }
    }
  }
  index++;
  return index;
}

double Tpe_term::C1_term2(const State_Jacobi &final_state,
                          const State_Jacobi &init_state) {
  double result = 0.0;

  // !!!! should n't have E conservation !!!!
  // energy conservation
  // if (final_state.E != init_state.E)
  //  return result;

  if ((final_state.J_2 != init_state.J_2) ||
      (final_state.T_2 != init_state.T_2))
    return result;
  // parity conservation
  int l12p = final_state.l12;
  int l12 = init_state.l12;
  int l3p = final_state.l3;
  int l3 = init_state.l3;

  int Par_Lp = l12p + l3p;
  int Par_L = l12 + l3;
  if ((Par_Lp % 2) != (Par_L % 2))
    return result;

  //
  // l state
  // cout << " bad ?? " << endl;
  int l_index = l_vec[l12p][l12][l3p][l3];
  // cout << "\t l_index = " << l_index << endl;
  //
  int n12p = final_state.n12;
  int n3p = final_state.n3;
  int n12 = init_state.n12;
  int n3 = init_state.n3;
  // cout << " bad ?? 2 " << endl;
  int nlp_index = wave.nl_vec[n12p][n3p][l12p][l3p];
  // cout << " bad ?? 3 " << endl;

  int nl_index = wave.nl_vec[n12][n3][l12][l3];
  // cout << " bad ?? 4 " << endl;
  // if (TpeCom.rank() == 0) {
  //   cout << "nlp_index = " << nlp_index << ": \t n12p=" << n12p
  //        << "\t n3p=" << n3p << "\t l12p=" << l12p << "\t l3p=" << l3p <<
  //        endl;
  //   cout << "nl_index = " << nl_index << ": \t n12=" << n12 << "\t n3=" << n3
  //        << "\t l12=" << l12 << "\t l3=" << l3 << endl;
  //   cout << "\t l_index = " << l_index << endl;
  // }

  int S_index = 3; // s_1 = 2, s_2 = 2

  //
  int T12p = final_state.T12_2 / 2;
  int T12 = init_state.T12_2 / 2;
  int S12p = final_state.S12_2 / 2;
  int S12 = init_state.S12_2 / 2;

  double TS_sixJ = 0.0;
  if (init_state.T_2 == 1) {
    TS_sixJ = T1S_sixJ[T12p][T12][S12p][S12];
  } else {
    if (T12p == 0 || T12 == 0) {
      cout << "Wrong at C1_term() TS_sixJ" << endl;
      exit(0);
    }
    TS_sixJ = T3S_sixJ[S12p][S12];
  }
  // cout << " bad ?? 5 TS_sizeJ =  "<< TS_sixJ<< endl;
  if (TS_sixJ == 0.0)
    return result;

  // phase
  int phase_t =
      init_state.J12_2 + final_state.j3_2 + init_state.J_2 + final_state.S12_2;
  phase_t = phase_t + final_state.T12_2 + init_state.T12_2 + init_state.T_2 + 1;
  phase_t = phase_t + final_state.l12 + final_state.l3 + init_state.l12 +
            init_state.l3;
  phase_t = phase_t / 2;
  int phase_C1 = phase(phase_t); // * phase(Par_L);
  //
  double part1_t, part1;
  part1_t = (final_state.J12_2 + 1) * (init_state.J12_2 + 1) *
            (final_state.j3_2 + 1) * (init_state.j3_2 + 1);
  // cout << " bad ?? 6 " << endl;
  part1 = std::sqrt(part1_t) * Hat_vec[T12p] * Hat_vec[T12] * Hat_vec[S12p] *
          Hat_vec[S12];
  // cout << " bad ?? 7 " << endl;
  double part2 = TS_sixJ;

  //
  // Gc1
  double part3 = 0;
  // t0
  int t02_min1 = std::abs(final_state.j3_2 - init_state.j3_2);
  int t02_max1 = (final_state.j3_2 + init_state.j3_2);
  int t02_min2 = std::abs(final_state.J12_2 - init_state.J12_2);
  int t02_max2 = (final_state.J12_2 + init_state.J12_2);

  int t02_min = std::max(t02_min1, t02_min2);
  int t02_max = std::min(t02_max1, t02_max2);
  if (t02_min > t02_max)
    return result;

  int t1_2_min1 = 2 * std::abs(l12p - l12);
  int t1_2_max1 = 2 * (l12p + l12);

  int t4_2_min1 = 2 * std::abs(l3p - l3);
  int t4_2_max1 = 2 * (l3p + l3);

  for (int t0_2 = t02_min; t0_2 <= t02_max; t0_2 = t0_2 + 2) {
    double G1 = sixJ.quick(final_state.J12_2, final_state.j3_2, init_state.J_2,
                           init_state.j3_2, init_state.J12_2, t0_2);
    if (G1 == 0.0)
      continue;
    G1 = G1 * phase(t0_2 / 2) * (t0_2 + 1);

    // t1

    int t1_2_min2 = std::abs(2 - t0_2);
    int t1_2_max2 = 2 + t0_2;
    int t1_2_min = std::max(t1_2_min1, t1_2_min2);
    int t1_2_max = std::min(t1_2_max1, t1_2_max2);

    int t4_2_min2 = t1_2_min2;
    int t4_2_max2 = t1_2_max2;
    int t4_2_min = std::max(t4_2_min1, t4_2_min2);
    int t4_2_max = std::min(t4_2_max1, t4_2_max2);

    if (t1_2_min > t1_2_max)
      continue;
    for (int t1_2 = t1_2_min; t1_2 <= t1_2_max; t1_2 = t1_2 + 2) {
      double G2 =
          ninJ.cal(2 * l12p, 2 * l12, t1_2, final_state.S12_2, init_state.S12_2,
                   2, final_state.J12_2, init_state.J12_2, t0_2);
      if (G2 == 0.0)
        continue;
      G2 = G2 * phase(t1_2 / 2) * (t1_2 + 1);
      // t4
      if (t4_2_min > t4_2_max)
        continue;
      for (int t4_2 = t4_2_min; t4_2 <= t4_2_max; t4_2 = t4_2 + 2) {
        double G3 = ninJ.cal(2 * l3p, 2 * l3, t4_2, 1, 1, 2, final_state.j3_2,
                             init_state.j3_2, t0_2);
        if (G3 == 0.0)
          continue;
        G3 = G3 * phase(t4_2 / 2) * (t4_2 + 1);
        double Gc1 = G1 * G2 * G3;
        // cout << " Gc1 = " << Gc1 << endl;
        int t0 = t0_2 / 2;
        int t1 = t1_2 / 2;
        int t4 = t4_2 / 2;
        // int t_index = t014_vec[t0][t1][t4];
        int t_index = t014_vec2[l_index][t0][t1][t4];

        // Ic1
        //#pragma omp parallel for reduction(+ : part3)
        for (int i = 0; i < Ic1_index[l_index].size(); i++) {
          double Ic1_val = Ic1_index[l_index][i].val;

          // cout << "i : " << i << "\t Ic1_val = " << Ic1_val << endl;

          int lamb_i = Ic1_index[l_index][i].lamb_i;
          int lamb_j = Ic1_index[l_index][i].lamb_j;
          int lamb_k = Ic1_index[l_index][i].lamb_k;
          int lamb_l = Ic1_index[l_index][i].lamb_l;
          int lamb_3 = Ic1_index[l_index][i].lamb_3;
          int lamb_4 = Ic1_index[l_index][i].lamb_4;

          // int size_hc1 = Hc1_state[l_index][i][t_index].size();
          // cout << "good ??/?" << endl;
          vector<Hc_struct> Hc1_s;
          int size_hc1 =
              Hc1_cal(l_index, t0, t1, t4, Ic1_index[l_index][i], Hc1_s);
          // cout << "\t size_hc1 = " << size_hc1 << "\t " << Hc1_s.size() <<
          // endl;
          if (size_hc1 < 0)
            continue;
          // if ( size_hc1 < 1)continue;
          for (int h = 0; h < size_hc1; h++) {
            // cout << "C1_term test 1 ?? " << endl;
            double Hc1_val = Hc1_s[h].val;
            // cout << "C1_term test 2 ?? " << endl;
            // cout << "h : " << h << "\t Hc1_val = " << Hc1_val << endl;

            int lbar = Hc1_s[h].lbar;
            int lbar12 = Hc1_s[h].lbar_12;
            int lbar3 = Hc1_s[h].lbar_3;
            int i_1 = Hc1_s[h].i_1;
            int i_2 = Hc1_s[h].i_2;
            int i_3 = Hc1_s[h].i_3;
            int i_4 = Hc1_s[h].i_4;

            int A = lamb_i + i_1;
            int B = lamb_j + i_2;
            int C = lamb_k + lamb_3 + i_3;
            int D = lamb_l + lamb_4 + i_4;

            if (lbar > wave.lbar_max) {
              cout << "Wrong at Tpe_term::C1_term  lbar > wave.lbar_max"
                   << endl;
              cout << "lbar = " << lbar
                   << "\t wave.lbar_max = " << wave.lbar_max << endl;
              exit(0);
            }
            // cout << "C1_term test 3 ?? " << endl;
            int lbar_index = wave.lbar_vec[lbar][lbar12][lbar3];
            // cout << "C1_term test 4 ?? " << endl;
            int klamb_index = wave.klamb_vec[lbar][A][B][C][D];
            // cout << "C1_term test 5 ?? " << endl;
            if (klamb_index < 0) {
              cout << "Wrong at Tpe_term::C1_term klamb_index <0 " << endl;
              cout << "A = " << A << "\t B = " << B << "\t C = " << C
                   << "\t D = " << D << endl;
              exit(0);
            }

            // cout<<"\t t_index : "<<t_index;
            /*
                        cout << "C1_term : ";
                        cout << "\t nl_index : " << nl_index;
                        cout << "\t nlp_index : " << nlp_index;
                        cout << "\t lbar_index : " << lbar_index;
                        cout << "\t lbar = " << lbar << "\t lba12 = " <<
               lbar12
                             << "\t lbar3 = " << lbar3 << endl;
                        cout << "\t klamb_index : " << klamb_index << endl;
                        cout << "\t A : " << A << "\t B : " << B << "\t C : "
               <<
               C
                             << "\t D : " << D << endl;
                             */
            // double PFglbarS =
            // wave.PFKglbarS_vec[S_index][nlp_index][nl_index]
            //                                    [lbar_index][klamb_index];

            double PFglbarS = wave.PFKglbarS_quick(
                nlp_index, nl_index, A, B, C, D, S_index, lbar, lbar12, lbar3);
            /*double PFglbarS =
                wave.PFKglbarS_rank_quick(nlp_index, nl_index, A, B, C, D,
                                          S_index, lbar, lbar12, lbar3);  */
            // double PFglbarS = 0.0;

            part3 += Gc1 * Ic1_val * Hc1_val * PFglbarS;
            /*
            cout << "Gc1 = " << Gc1 << endl;
            cout << " \t PFglbarS = " << PFglbarS << endl;
            cout << "  +sum val = " << Gc1 * Ic1_val * Hc1_val * PFglbarS
                 << endl;
                 */
          }
        }
      }
    }
  }

  result = phase_C1 * pf_tpe_c1 * part1 * part2 * part3;
  /*
  cout << "phase_C1 = " << phase_C1 << endl;
  cout << "pf_tpe_c1 = " << pf_tpe_c1 << endl;
  cout << "part1 = " << part1 << endl;
  cout << "part2 = " << part2 << endl;
  cout << "part3 = " << part3 << endl;
  cout << "result = " << result << endl;
  // cout<<"PFglbarS = "<<wave.PFKglbarS_vec[3][0][0][13][121]<<endl;
  /*
  int lbar = 1;

  int A = wave.klamb_state[lbar][68].lamb12_p;
  int B = wave.klamb_state[lbar][68].lamb12;
  int C = wave.klamb_state[lbar][68].lamb3_p;
  int D = wave.klamb_state[lbar][68].lamb3;

  int klamb_index = wave.klamb_vec[lbar][A][B][C][D];
  cout<<"klamb : "<<klamb_index<<endl;
  cout<<"\t A : "<<A<<"\t B : "<<B<<"\t C : "<<C<<"\t D : "<<D<<endl;
    double PF = wave.PFKglbarS_vec_cal2(0,0,A,B,B,D,3,13);
  cout<<"\t PF = "<<PF<<endl;

  cout<<"\t lbar :"<<wave.lbar_state[13].lbar<<"\t lbar12
  :"<<wave.lbar_state[13].lbar12
    <<"\t lbar3 :"<<wave.lbar_state[13].lbar3<<endl;

  for(int i=0;i<wave.glbarS_vec[3][13][3].size();i++){
    //cout<<wave.glbarS2_vec[3][13][3][i]<<endl;
  }
  */

  return result;
}

double Tpe_term::C1_term2_check(const State_Jacobi &final_state,
                                const State_Jacobi &init_state) {
  double result = 0.0;

  std::ofstream file;
  file.open("data/C1_term_check.dat");
  file << "\t --- Jaco info --- " << endl;
  file << "num: \t"
       << "2*T \t"
       << "2*T12 \t"
       << "2*J \t"
       << "2*J12 \t"
       << "2*j3 \t"
       << "2*S12 \t"
       << "l12 \t"
       << "l3 \t"
       << "n12 \t"
       << "n3 \t"
       << "E \t"
       << "index \t"
       << "JT_channel \t"
       << "flag" << endl;

  file << "f :\t";
  file << final_state.T_2 << "\t" << final_state.T12_2 << "\t"
       << final_state.J_2 << "\t" << final_state.J12_2 << "\t";
  file << final_state.j3_2 << "\t";
  file << final_state.S12_2 << "\t" << final_state.l12 << "\t" << final_state.l3
       << "\t" << final_state.n12 << "\t";
  file << final_state.n3 << "\t" << final_state.E << "\t" << final_state.index
       << "\t";
  file << final_state.JT_channel << "\t\t" << final_state.flag << endl;

  file << "i :\t";
  file << init_state.T_2 << "\t" << init_state.T12_2 << "\t" << init_state.J_2
       << "\t" << init_state.J12_2 << "\t";
  file << init_state.j3_2 << "\t";
  file << init_state.S12_2 << "\t" << init_state.l12 << "\t" << init_state.l3
       << "\t" << init_state.n12 << "\t";
  file << init_state.n3 << "\t" << init_state.E << "\t" << init_state.index
       << "\t";
  file << init_state.JT_channel << "\t\t" << init_state.flag << endl;
  file << "\t --------- --------- " << endl;
  // !!!! should n't have E conservation !!!!
  // energy conservation
  // if (final_state.E != init_state.E)
  //  return result;

  if ((final_state.J_2 != init_state.J_2) ||
      (final_state.T_2 != init_state.T_2))
    return result;
  // parity conservation
  int l12p = final_state.l12;
  int l12 = init_state.l12;
  int l3p = final_state.l3;
  int l3 = init_state.l3;

  int Par_Lp = l12p + l3p;
  int Par_L = l12 + l3;
  if ((Par_Lp % 2) != (Par_L % 2))
    return result;

  //
  // l state
  // cout << " bad ?? " << endl;
  int l_index = l_vec[l12p][l12][l3p][l3];
  // cout << "\t l_index = " << l_index << endl;
  //
  int n12p = final_state.n12;
  int n3p = final_state.n3;
  int n12 = init_state.n12;
  int n3 = init_state.n3;
  // cout << " bad ?? 2 " << endl;
  int nlp_index = wave.nl_vec[n12p][n3p][l12p][l3p];
  // cout << " bad ?? 3 " << endl;

  int nl_index = wave.nl_vec[n12][n3][l12][l3];
  // cout << " bad ?? 4 " << endl;
  // if (TpeCom.rank() == 0) {
  //   cout << "nlp_index = " << nlp_index << ": \t n12p=" << n12p
  //        << "\t n3p=" << n3p << "\t l12p=" << l12p << "\t l3p=" << l3p <<
  //        endl;
  //   cout << "nl_index = " << nl_index << ": \t n12=" << n12 << "\t n3=" << n3
  //        << "\t l12=" << l12 << "\t l3=" << l3 << endl;
  //   cout << "\t l_index = " << l_index << endl;
  // }

  int S_index = 3; // s_1 = 2, s_2 = 2

  //
  int T12p = final_state.T12_2 / 2;
  int T12 = init_state.T12_2 / 2;
  int S12p = final_state.S12_2 / 2;
  int S12 = init_state.S12_2 / 2;

  double TS_sixJ = 0.0;
  if (init_state.T_2 == 1) {
    TS_sixJ = T1S_sixJ[T12p][T12][S12p][S12];
  } else {
    if (T12p == 0 || T12 == 0) {
      cout << "Wrong at C1_term() TS_sixJ" << endl;
      exit(0);
    }
    TS_sixJ = T3S_sixJ[S12p][S12];
  }
  // cout << " bad ?? 5 TS_sizeJ =  "<< TS_sixJ<< endl;
  if (TS_sixJ == 0.0)
    return result;

  // phase
  int phase_t =
      init_state.J12_2 + final_state.j3_2 + init_state.J_2 + final_state.S12_2;
  phase_t = phase_t + final_state.T12_2 + init_state.T12_2 + init_state.T_2 + 1;
  phase_t = phase_t + final_state.l12 + final_state.l3 + init_state.l12 +
            init_state.l3;
  phase_t = phase_t / 2;
  int phase_C1 = phase(phase_t); // * phase(Par_L);
  //
  double part1_t, part1;
  part1_t = (final_state.J12_2 + 1) * (init_state.J12_2 + 1) *
            (final_state.j3_2 + 1) * (init_state.j3_2 + 1);
  // cout << " bad ?? 6 " << endl;
  part1 = std::sqrt(part1_t) * Hat_vec[T12p] * Hat_vec[T12] * Hat_vec[S12p] *
          Hat_vec[S12];
  // cout << " bad ?? 7 " << endl;
  double part2 = TS_sixJ;

  file << "\t --- C1_term = phase_C1 * pf_tpe_c1 * part1 * part2 * part3 ---"
       << endl;
  file << "\t phase_C1 = " << phase_C1 << "\t pf_tpe_c1 = " << pf_tpe_c1
       << "\t part1 = " << part1 << "\t part2 = " << part2 << endl;
  file << "\t --- --- --- --- ---" << endl << endl;
  file << "\t --- part3 info : --- " << endl;
  //
  // Gc1
  double part3 = 0;
  // t0
  int t02_min1 = std::abs(final_state.j3_2 - init_state.j3_2);
  int t02_max1 = (final_state.j3_2 + init_state.j3_2);
  int t02_min2 = std::abs(final_state.J12_2 - init_state.J12_2);
  int t02_max2 = (final_state.J12_2 + init_state.J12_2);

  int t02_min = std::max(t02_min1, t02_min2);
  int t02_max = std::min(t02_max1, t02_max2);
  if (t02_min > t02_max)
    return result;

  int t1_2_min1 = 2 * std::abs(l12p - l12);
  int t1_2_max1 = 2 * (l12p + l12);

  int t4_2_min1 = 2 * std::abs(l3p - l3);
  int t4_2_max1 = 2 * (l3p + l3);

  for (int t0_2 = t02_min; t0_2 <= t02_max; t0_2 = t0_2 + 2) {
    double G1 = sixJ.quick(final_state.J12_2, final_state.j3_2, init_state.J_2,
                           init_state.j3_2, init_state.J12_2, t0_2);
    if (G1 == 0.0)
      continue;
    G1 = G1 * phase(t0_2 / 2) * (t0_2 + 1);

    // t1

    int t1_2_min2 = std::abs(2 - t0_2);
    int t1_2_max2 = 2 + t0_2;
    int t1_2_min = std::max(t1_2_min1, t1_2_min2);
    int t1_2_max = std::min(t1_2_max1, t1_2_max2);

    int t4_2_min2 = t1_2_min2;
    int t4_2_max2 = t1_2_max2;
    int t4_2_min = std::max(t4_2_min1, t4_2_min2);
    int t4_2_max = std::min(t4_2_max1, t4_2_max2);

    if (t1_2_min > t1_2_max)
      continue;
    for (int t1_2 = t1_2_min; t1_2 <= t1_2_max; t1_2 = t1_2 + 2) {
      double G2 =
          ninJ.cal(2 * l12p, 2 * l12, t1_2, final_state.S12_2, init_state.S12_2,
                   2, final_state.J12_2, init_state.J12_2, t0_2);
      if (G2 == 0.0)
        continue;
      G2 = G2 * phase(t1_2 / 2) * (t1_2 + 1);
      // t4
      if (t4_2_min > t4_2_max)
        continue;
      for (int t4_2 = t4_2_min; t4_2 <= t4_2_max; t4_2 = t4_2 + 2) {
        double G3 = ninJ.cal(2 * l3p, 2 * l3, t4_2, 1, 1, 2, final_state.j3_2,
                             init_state.j3_2, t0_2);
        if (G3 == 0.0)
          continue;
        G3 = G3 * phase(t4_2 / 2) * (t4_2 + 1);
        double Gc1 = G1 * G2 * G3;
        // cout << " Gc1 = " << Gc1 << endl;
        int t0 = t0_2 / 2;
        int t1 = t1_2 / 2;
        int t4 = t4_2 / 2;
        // int t_index = t014_vec[t0][t1][t4];
        int t_index = t014_vec2[l_index][t0][t1][t4];

        // Ic1
        //#pragma omp parallel for reduction(+ : part3)
        for (int i = 0; i < Ic1_index[l_index].size(); i++) {
          double Ic1_val = Ic1_index[l_index][i].val;

          // cout << "i : " << i << "\t Ic1_val = " << Ic1_val << endl;

          int lamb_i = Ic1_index[l_index][i].lamb_i;
          int lamb_j = Ic1_index[l_index][i].lamb_j;
          int lamb_k = Ic1_index[l_index][i].lamb_k;
          int lamb_l = Ic1_index[l_index][i].lamb_l;
          int lamb_3 = Ic1_index[l_index][i].lamb_3;
          int lamb_4 = Ic1_index[l_index][i].lamb_4;

          // int size_hc1 = Hc1_state[l_index][i][t_index].size();
          // cout << "good ??/?" << endl;
          vector<Hc_struct> Hc1_s;
          int size_hc1 =
              Hc1_cal(l_index, t0, t1, t4, Ic1_index[l_index][i], Hc1_s);
          // cout << "\t size_hc1 = " << size_hc1 << "\t " << Hc1_s.size() <<
          // endl;
          if (size_hc1 < 0)
            continue;
          // if ( size_hc1 < 1)continue;
          for (int h = 0; h < size_hc1; h++) {
            // cout << "C1_term test 1 ?? " << endl;
            double Hc1_val = Hc1_s[h].val;
            // cout << "C1_term test 2 ?? " << endl;
            // cout << "h : " << h << "\t Hc1_val = " << Hc1_val << endl;

            int lbar = Hc1_s[h].lbar;
            int lbar12 = Hc1_s[h].lbar_12;
            int lbar3 = Hc1_s[h].lbar_3;
            int i_1 = Hc1_s[h].i_1;
            int i_2 = Hc1_s[h].i_2;
            int i_3 = Hc1_s[h].i_3;
            int i_4 = Hc1_s[h].i_4;

            int A = lamb_i + i_1;
            int B = lamb_j + i_2;
            int C = lamb_k + lamb_3 + i_3;
            int D = lamb_l + lamb_4 + i_4;

            if (lbar > wave.lbar_max) {
              cout << "Wrong at Tpe_term::C1_term  lbar > wave.lbar_max"
                   << endl;
              cout << "lbar = " << lbar
                   << "\t wave.lbar_max = " << wave.lbar_max << endl;
              exit(0);
            }
            // cout << "C1_term test 3 ?? " << endl;
            int lbar_index = wave.lbar_vec[lbar][lbar12][lbar3];
            // cout << "C1_term test 4 ?? " << endl;
            int klamb_index = wave.klamb_vec[lbar][A][B][C][D];
            // cout << "C1_term test 5 ?? " << endl;
            if (klamb_index < 0) {
              cout << "Wrong at Tpe_term::C1_term klamb_index <0 " << endl;
              cout << "A = " << A << "\t B = " << B << "\t C = " << C
                   << "\t D = " << D << endl;
              exit(0);
            }

            // cout<<"\t t_index : "<<t_index;
            /*
                        cout << "C1_term : ";
                        cout << "\t nl_index : " << nl_index;
                        cout << "\t nlp_index : " << nlp_index;
                        cout << "\t lbar_index : " << lbar_index;
                        cout << "\t lbar = " << lbar << "\t lba12 = " <<
               lbar12
                             << "\t lbar3 = " << lbar3 << endl;
                        cout << "\t klamb_index : " << klamb_index << endl;
                        cout << "\t A : " << A << "\t B : " << B << "\t C : "
               <<
               C
                             << "\t D : " << D << endl;
                             */
            // double PFglbarS =
            // wave.PFKglbarS_vec[S_index][nlp_index][nl_index]
            //                                    [lbar_index][klamb_index];

            double PFglbarS = wave.PFKglbarS_quick(
                nlp_index, nl_index, A, B, C, D, S_index, lbar, lbar12, lbar3);
            /*double PFglbarS =
                wave.PFKglbarS_rank_quick(nlp_index, nl_index, A, B, C, D,
                                          S_index, lbar, lbar12, lbar3);  */
            // double PFglbarS = 0.0;

            part3 += Gc1 * Ic1_val * Hc1_val * PFglbarS;

            file << "Gc1 = " << Gc1 << "\t Ic1 = " << Ic1_val
                 << "\t Hc1 = " << Hc1_val;
            file << " \t PFglbarS = " << PFglbarS;
            file << "\t  +part3 val = " << Gc1 * Ic1_val * Hc1_val * PFglbarS
                 << endl;
          }
        }
      }
    }
  }

  result = phase_C1 * pf_tpe_c1 * part1 * part2 * part3;

  file << "\t --- part3 = " << part3 << " --- " << endl;
  file << "\t === C1_term : " << result << " === " << endl;

  file.close();
  /*
  cout << "phase_C1 = " << phase_C1 << endl;
  cout << "pf_tpe_c1 = " << pf_tpe_c1 << endl;
  cout << "part1 = " << part1 << endl;
  cout << "part2 = " << part2 << endl;
  cout << "part3 = " << part3 << endl;
  cout << "result = " << result << endl;
  // cout<<"PFglbarS = "<<wave.PFKglbarS_vec[3][0][0][13][121]<<endl;
  /*
  int lbar = 1;

  int A = wave.klamb_state[lbar][68].lamb12_p;
  int B = wave.klamb_state[lbar][68].lamb12;
  int C = wave.klamb_state[lbar][68].lamb3_p;
  int D = wave.klamb_state[lbar][68].lamb3;

  int klamb_index = wave.klamb_vec[lbar][A][B][C][D];
  cout<<"klamb : "<<klamb_index<<endl;
  cout<<"\t A : "<<A<<"\t B : "<<B<<"\t C : "<<C<<"\t D : "<<D<<endl;
    double PF = wave.PFKglbarS_vec_cal2(0,0,A,B,B,D,3,13);
  cout<<"\t PF = "<<PF<<endl;

  cout<<"\t lbar :"<<wave.lbar_state[13].lbar<<"\t lbar12
  :"<<wave.lbar_state[13].lbar12
    <<"\t lbar3 :"<<wave.lbar_state[13].lbar3<<endl;

  for(int i=0;i<wave.glbarS_vec[3][13][3].size();i++){
    //cout<<wave.glbarS2_vec[3][13][3][i]<<endl;
  }
  */

  return result;
}

double Tpe_term::C3_term2(const State_Jacobi &final_state,
                          const State_Jacobi &init_state) {
  double result = 0.0;

  // !!!! should n't have E conservation !!!!
  // energy conservation
  //  if (final_state.E != init_state.E)
  //    return result;

  if ((final_state.J_2 != init_state.J_2) ||
      (final_state.T_2 != init_state.T_2))
    return result;
  // parity conservation
  int l12p = final_state.l12;
  int l12 = init_state.l12;
  int l3p = final_state.l3;
  int l3 = init_state.l3;

  int Par_Lp = l12p + l3p;
  int Par_L = l12 + l3;
  if ((Par_Lp % 2) != (Par_L % 2))
    return result;

  //
  // l state
  int l_index = l_vec[l12p][l12][l3p][l3];
  //
  int n12p = final_state.n12;
  int n3p = final_state.n3;
  int n12 = init_state.n12;
  int n3 = init_state.n3;
  int nlp_index = wave.nl_vec[n12p][n3p][l12p][l3p];
  int nl_index = wave.nl_vec[n12][n3][l12][l3];
  // sint S_index = 3; // s_1 = 2, s_2 = 2

  //
  int T12p = final_state.T12_2 / 2;
  int T12 = init_state.T12_2 / 2;
  int S12p = final_state.S12_2 / 2;
  int S12 = init_state.S12_2 / 2;

  double TS_sixJ = 0.0;
  if (init_state.T_2 == 1) {
    TS_sixJ = T1S_sixJ[T12p][T12][S12p][S12];
  } else {
    if (T12p == 0 || T12 == 0) {
      cout << "Wrong at C1_term() TS_sixJ" << endl;
      exit(0);
    }
    TS_sixJ = T3S_sixJ[S12p][S12];
  }
  if (TS_sixJ == 0.0)
    return result;

  // phase
  int phase_t =
      init_state.J12_2 + final_state.j3_2 + init_state.J_2 + final_state.S12_2;
  phase_t = phase_t + final_state.T12_2 + init_state.T12_2 + init_state.T_2 + 1;
  phase_t = phase_t + final_state.l12 + final_state.l3 + init_state.l12 +
            init_state.l3;
  phase_t = phase_t / 2;
  int phase_C3 = -1 * phase(phase_t); // * phase(Par_L);
  //
  double part1_t, part1;
  part1_t = (final_state.J12_2 + 1) * (init_state.J12_2 + 1) *
            (final_state.j3_2 + 1) * (init_state.j3_2 + 1);
  part1 = std::sqrt(part1_t) * Hat_vec[T12p] * Hat_vec[T12] * Hat_vec[S12p] *
          Hat_vec[S12];

  double part2 = TS_sixJ;
  //
  // Gc1
  double part3 = 0;
  // t0
  int t02_min1 = std::abs(final_state.j3_2 - init_state.j3_2);
  int t02_max1 = (final_state.j3_2 + init_state.j3_2);
  int t02_min2 = std::abs(final_state.J12_2 - init_state.J12_2);
  int t02_max2 = (final_state.J12_2 + init_state.J12_2);

  int t02_min = std::max(t02_min1, t02_min2);
  int t02_max = std::min(t02_max1, t02_max2);
  if (t02_min > t02_max)
    return result;

  int t1_2_min1 = 2 * std::abs(l12p - l12);
  int t1_2_max1 = 2 * (l12p + l12);

  int t4_2_min1 = 2 * std::abs(l3p - l3);
  int t4_2_max1 = 2 * (l3p + l3);

  for (int t0_2 = t02_min; t0_2 <= t02_max; t0_2 = t0_2 + 2) {
    double G1 = sixJ.quick(final_state.J12_2, final_state.j3_2, init_state.J_2,
                           init_state.j3_2, init_state.J12_2, t0_2);
    if (G1 == 0.0)
      continue;
    G1 = G1 * phase(t0_2 / 2) * (t0_2 + 1);

    // t1

    int t1_2_min2 = std::abs(2 - t0_2);
    int t1_2_max2 = 2 + t0_2;
    int t1_2_min = std::max(t1_2_min1, t1_2_min2);
    int t1_2_max = std::min(t1_2_max1, t1_2_max2);

    int t4_2_min2 = t1_2_min2;
    int t4_2_max2 = t1_2_max2;
    int t4_2_min = std::max(t4_2_min1, t4_2_min2);
    int t4_2_max = std::min(t4_2_max1, t4_2_max2);

    if (t1_2_min > t1_2_max)
      continue;
    for (int t1_2 = t1_2_min; t1_2 <= t1_2_max; t1_2 = t1_2 + 2) {
      double G2 =
          ninJ.cal(2 * l12p, 2 * l12, t1_2, final_state.S12_2, init_state.S12_2,
                   2, final_state.J12_2, init_state.J12_2, t0_2);
      if (G2 == 0.0)
        continue;
      G2 = G2 * phase(t1_2 / 2) * (t1_2 + 1);
      // t4
      if (t4_2_min > t4_2_max)
        continue;
      for (int t4_2 = t4_2_min; t4_2 <= t4_2_max; t4_2 = t4_2 + 2) {
        double G3 = ninJ.cal(2 * l3p, 2 * l3, t4_2, 1, 1, 2, final_state.j3_2,
                             init_state.j3_2, t0_2);
        if (G3 == 0.0)
          continue;
        G3 = G3 * phase(t4_2 / 2) * (t4_2 + 1);
        double Gc3 = G1 * G2 * G3;

        int t0 = t0_2 / 2;
        int t1 = t1_2 / 2;
        int t4 = t4_2 / 2;
        // int t_index = t014_vec[t0][t1][t4];
        int t_index = t014_vec2[l_index][t0][t1][t4];

        // Ic1
        //#pragma omp parallel for reduction(+ : part3)
        for (int i = 0; i < Ic3_index[l_index].size(); i++) {
          double Ic3_val = Ic3_index[l_index][i].val;

          // cout<<"i : "<<i<<"\t Ic1_val = "<<Ic1_val<<endl;

          int lamb_i = Ic3_index[l_index][i].lamb_i;
          int lamb_j = Ic3_index[l_index][i].lamb_j;
          int lamb_k = Ic3_index[l_index][i].lamb_k;
          int lamb_l = Ic3_index[l_index][i].lamb_l;
          int lamb_3 = Ic3_index[l_index][i].lamb_3;
          int lamb_4 = Ic3_index[l_index][i].lamb_4;
          int s_1 = Ic3_index[l_index][i].s_1;
          int s_2 = Ic3_index[l_index][i].s_2;
          int S_index = s_1 / 2 + s_2;

          // int size_hc3 = Hc3_state[l_index][i][t_index].size();
          vector<Hc_struct> Hc3_s;
          int size_hc3 =
              Hc3_cal(l_index, t0, t1, t4, Ic3_index[l_index][i], Hc3_s);
          // cout << size_hc3 << "\t Hc3_s size :" << Hc3_s.size() << endl;
          if (size_hc3 < 1)
            continue;

          for (int h = 0; h < size_hc3; h++) {
            double Hc3_val = Hc3_s[h].val;

            // cout<<"h : "<<h<<"\t Hc1_val = "<<Hc1_val<<endl;

            int lbar = Hc3_s[h].lbar;
            int lbar12 = Hc3_s[h].lbar_12;
            int lbar3 = Hc3_s[h].lbar_3;
            int i_1 = Hc3_s[h].i_1;
            int i_2 = Hc3_s[h].i_2;
            int i_3 = Hc3_s[h].i_3;
            int i_4 = Hc3_s[h].i_4;

            int A = lamb_i + i_1;
            int B = lamb_j + i_2;
            int C = lamb_k + lamb_3 + i_3;
            int D = lamb_l + lamb_4 + i_4;

            if (lbar > wave.lbar_max) {
              cout << "Wrong at Tpe_term::C3_term  lbar > wave.lbar_max"
                   << endl;
              exit(0);
            }
            int lbar_index = wave.lbar_vec[lbar][lbar12][lbar3];
            int klamb_index = wave.klamb_vec[lbar][A][B][C][D];
            if (klamb_index < 0) {
              cout << "Wrong at Tpe_term::C3_term klamb_index <0 " << endl;
              exit(0);
            }
            /*
            //cout<<"\t t_index : "<<t_index;

            */
            // double PFglbarS =
            // wave.PFKglbarS_vec[S_index][nlp_index][nl_index]
            //                                    [lbar_index][klamb_index];
            double PFglbarS =
                wave.PFKglbarS_quick(nlp_index, nl_index, A, B, C, D, S_index,
                                     lbar, lbar12, lbar3);
            /*double PFglbarS = 0.0;
            /*
            cout << "C3 term : ";
            cout << "\t nl_index : " << nl_index;
            cout << "\t nl_index : " << nl_index;
            cout << "\t nlp_index : " << nlp_index;
            cout << "\t lbar_index : " << lbar_index;
            cout << "\t lbar = " << lbar << "\t lba12 = " << lbar12
                 << "\t lbar3 =" << lbar3 << endl;
            cout << "\t klamb_index : " << klamb_index << endl;
            cout << "\t A : " << A << "\t B : " << B << "\t C : " << C
                 << "\t D : " << D << endl;
                 */
            // double PFglbarS = wave.PFKglbarS_quick(nlp_index, nl_index, A,
            // B, C,
            //                                       D, S_index, lbar_index);
            part3 += Gc3 * Ic3_val * Hc3_val * PFglbarS;
            /*
            cout<<"Gc1 = "<<Gc1<<endl;
            cout<<" \t PFglbarS = "<<PFglbarS<<endl;
            cout<<"  +sum val = "<<Gc1 * Ic1_val * Hc1_val * PFglbarS<<endl;
            */
          }
        }
      }
    }
  }

  result = phase_C3 * pf_tpe_c3 * part1 * part2 * part3;
  /*
  cout<<"phase_C1 = "<<phase_C1<<endl;
  cout<<"pf_tpe_c1 = "<<pf_tpe_c1<<endl;
  cout<<"part1 = "<<part1<<endl;
  cout<<"part2 = "<<part2<<endl;
  cout<<"part3 = "<<part3<<endl;
  cout<<"result = "<<result<<endl;
  cout<<"PFglbarS = "<<wave.PFKglbarS_vec[3][0][0][13][121]<<endl;

  int lbar = 1;

  int A = wave.klamb_state[lbar][68].lamb12_p;
  int B = wave.klamb_state[lbar][68].lamb12;
  int C = wave.klamb_state[lbar][68].lamb3_p;
  int D = wave.klamb_state[lbar][68].lamb3;

  int klamb_index = wave.klamb_vec[lbar][A][B][C][D];
  cout<<"klamb : "<<klamb_index<<endl;
  cout<<"\t A : "<<A<<"\t B : "<<B<<"\t C : "<<C<<"\t D : "<<D<<endl;
    double PF = wave.PFKglbarS_vec_cal2(0,0,A,B,B,D,3,13);
  cout<<"\t PF = "<<PF<<endl;

  cout<<"\t lbar :"<<wave.lbar_state[13].lbar<<"\t lbar12
  :"<<wave.lbar_state[13].lbar12
    <<"\t lbar3 :"<<wave.lbar_state[13].lbar3<<endl;

  for(int i=0;i<wave.glbarS_vec[3][13][3].size();i++){
    //cout<<wave.glbarS2_vec[3][13][3][i]<<endl;
  }
  */

  return result;
}

double Tpe_term::C3_term2_check(const State_Jacobi &final_state,
                                const State_Jacobi &init_state) {
  double result = 0.0;

  // !!!! should n't have E conservation !!!!
  // energy conservation
  //  if (final_state.E != init_state.E)
  //    return result;
  std::ofstream file;
  file.open("data/C3_term_check.dat");
  file << "\t --- Jaco info --- " << endl;
  file << "num: \t"
       << "2*T \t"
       << "2*T12 \t"
       << "2*J \t"
       << "2*J12 \t"
       << "2*j3 \t"
       << "2*S12 \t"
       << "l12 \t"
       << "l3 \t"
       << "n12 \t"
       << "n3 \t"
       << "E \t"
       << "index \t"
       << "JT_channel \t"
       << "flag" << endl;

  file << "f :\t";
  file << final_state.T_2 << "\t" << final_state.T12_2 << "\t"
       << final_state.J_2 << "\t" << final_state.J12_2 << "\t";
  file << final_state.j3_2 << "\t";
  file << final_state.S12_2 << "\t" << final_state.l12 << "\t" << final_state.l3
       << "\t" << final_state.n12 << "\t";
  file << final_state.n3 << "\t" << final_state.E << "\t" << final_state.index
       << "\t";
  file << final_state.JT_channel << "\t\t" << final_state.flag << endl;

  file << "i :\t";
  file << init_state.T_2 << "\t" << init_state.T12_2 << "\t" << init_state.J_2
       << "\t" << init_state.J12_2 << "\t";
  file << init_state.j3_2 << "\t";
  file << init_state.S12_2 << "\t" << init_state.l12 << "\t" << init_state.l3
       << "\t" << init_state.n12 << "\t";
  file << init_state.n3 << "\t" << init_state.E << "\t" << init_state.index
       << "\t";
  file << init_state.JT_channel << "\t\t" << init_state.flag << endl;
  file << "\t --------- --------- " << endl;

  if ((final_state.J_2 != init_state.J_2) ||
      (final_state.T_2 != init_state.T_2))
    return result;
  // parity conservation
  int l12p = final_state.l12;
  int l12 = init_state.l12;
  int l3p = final_state.l3;
  int l3 = init_state.l3;

  int Par_Lp = l12p + l3p;
  int Par_L = l12 + l3;
  if ((Par_Lp % 2) != (Par_L % 2))
    return result;

  //
  // l state
  int l_index = l_vec[l12p][l12][l3p][l3];
  //
  int n12p = final_state.n12;
  int n3p = final_state.n3;
  int n12 = init_state.n12;
  int n3 = init_state.n3;
  int nlp_index = wave.nl_vec[n12p][n3p][l12p][l3p];
  int nl_index = wave.nl_vec[n12][n3][l12][l3];
  // sint S_index = 3; // s_1 = 2, s_2 = 2

  //
  int T12p = final_state.T12_2 / 2;
  int T12 = init_state.T12_2 / 2;
  int S12p = final_state.S12_2 / 2;
  int S12 = init_state.S12_2 / 2;

  double TS_sixJ = 0.0;
  if (init_state.T_2 == 1) {
    TS_sixJ = T1S_sixJ[T12p][T12][S12p][S12];
  } else {
    if (T12p == 0 || T12 == 0) {
      cout << "Wrong at C1_term() TS_sixJ" << endl;
      exit(0);
    }
    TS_sixJ = T3S_sixJ[S12p][S12];
  }
  if (TS_sixJ == 0.0)
    return result;

  // phase
  int phase_t =
      init_state.J12_2 + final_state.j3_2 + init_state.J_2 + final_state.S12_2;
  phase_t = phase_t + final_state.T12_2 + init_state.T12_2 + init_state.T_2 + 1;
  phase_t = phase_t + final_state.l12 + final_state.l3 + init_state.l12 +
            init_state.l3;
  phase_t = phase_t / 2;
  int phase_C3 = -1 * phase(phase_t); // * phase(Par_L);
  //
  double part1_t, part1;
  part1_t = (final_state.J12_2 + 1) * (init_state.J12_2 + 1) *
            (final_state.j3_2 + 1) * (init_state.j3_2 + 1);
  part1 = std::sqrt(part1_t) * Hat_vec[T12p] * Hat_vec[T12] * Hat_vec[S12p] *
          Hat_vec[S12];

  double part2 = TS_sixJ;
  //
  file << "\t --- C3_term = phase_C3 * pf_tpe_c3 * part1 * part2 * part3; ---"
       << endl;
  file << "\t phase_C3 = " << phase_C3 << "\t pf_tpe_c3 = " << pf_tpe_c3
       << "\t part1 = " << part1 << "\t part2 = " << part2 << endl;
  file << "\t --- --- --- --- ---" << endl << endl;
  file << "\t --- part3 info : --- " << endl;
  // Gc1
  double part3 = 0;
  // t0
  int t02_min1 = std::abs(final_state.j3_2 - init_state.j3_2);
  int t02_max1 = (final_state.j3_2 + init_state.j3_2);
  int t02_min2 = std::abs(final_state.J12_2 - init_state.J12_2);
  int t02_max2 = (final_state.J12_2 + init_state.J12_2);

  int t02_min = std::max(t02_min1, t02_min2);
  int t02_max = std::min(t02_max1, t02_max2);
  if (t02_min > t02_max)
    return result;

  int t1_2_min1 = 2 * std::abs(l12p - l12);
  int t1_2_max1 = 2 * (l12p + l12);

  int t4_2_min1 = 2 * std::abs(l3p - l3);
  int t4_2_max1 = 2 * (l3p + l3);

  for (int t0_2 = t02_min; t0_2 <= t02_max; t0_2 = t0_2 + 2) {
    double G1 = sixJ.quick(final_state.J12_2, final_state.j3_2, init_state.J_2,
                           init_state.j3_2, init_state.J12_2, t0_2);
    if (G1 == 0.0)
      continue;
    G1 = G1 * phase(t0_2 / 2) * (t0_2 + 1);

    // t1

    int t1_2_min2 = std::abs(2 - t0_2);
    int t1_2_max2 = 2 + t0_2;
    int t1_2_min = std::max(t1_2_min1, t1_2_min2);
    int t1_2_max = std::min(t1_2_max1, t1_2_max2);

    int t4_2_min2 = t1_2_min2;
    int t4_2_max2 = t1_2_max2;
    int t4_2_min = std::max(t4_2_min1, t4_2_min2);
    int t4_2_max = std::min(t4_2_max1, t4_2_max2);

    if (t1_2_min > t1_2_max)
      continue;
    for (int t1_2 = t1_2_min; t1_2 <= t1_2_max; t1_2 = t1_2 + 2) {
      double G2 =
          ninJ.cal(2 * l12p, 2 * l12, t1_2, final_state.S12_2, init_state.S12_2,
                   2, final_state.J12_2, init_state.J12_2, t0_2);
      if (G2 == 0.0)
        continue;
      G2 = G2 * phase(t1_2 / 2) * (t1_2 + 1);
      // t4
      if (t4_2_min > t4_2_max)
        continue;
      for (int t4_2 = t4_2_min; t4_2 <= t4_2_max; t4_2 = t4_2 + 2) {
        double G3 = ninJ.cal(2 * l3p, 2 * l3, t4_2, 1, 1, 2, final_state.j3_2,
                             init_state.j3_2, t0_2);
        if (G3 == 0.0)
          continue;
        G3 = G3 * phase(t4_2 / 2) * (t4_2 + 1);
        double Gc3 = G1 * G2 * G3;

        int t0 = t0_2 / 2;
        int t1 = t1_2 / 2;
        int t4 = t4_2 / 2;
        // int t_index = t014_vec[t0][t1][t4];
        int t_index = t014_vec2[l_index][t0][t1][t4];

        // Ic1
        //#pragma omp parallel for reduction(+ : part3)
        for (int i = 0; i < Ic3_index[l_index].size(); i++) {
          double Ic3_val = Ic3_index[l_index][i].val;

          // cout<<"i : "<<i<<"\t Ic1_val = "<<Ic1_val<<endl;

          int lamb_i = Ic3_index[l_index][i].lamb_i;
          int lamb_j = Ic3_index[l_index][i].lamb_j;
          int lamb_k = Ic3_index[l_index][i].lamb_k;
          int lamb_l = Ic3_index[l_index][i].lamb_l;
          int lamb_3 = Ic3_index[l_index][i].lamb_3;
          int lamb_4 = Ic3_index[l_index][i].lamb_4;
          int s_1 = Ic3_index[l_index][i].s_1;
          int s_2 = Ic3_index[l_index][i].s_2;
          int S_index = s_1 / 2 + s_2;

          // int size_hc3 = Hc3_state[l_index][i][t_index].size();
          vector<Hc_struct> Hc3_s;
          int size_hc3 =
              Hc3_cal(l_index, t0, t1, t4, Ic3_index[l_index][i], Hc3_s);
          // cout << size_hc3 << "\t Hc3_s size :" << Hc3_s.size() << endl;
          if (size_hc3 < 1)
            continue;

          for (int h = 0; h < size_hc3; h++) {
            double Hc3_val = Hc3_s[h].val;

            // cout<<"h : "<<h<<"\t Hc1_val = "<<Hc1_val<<endl;

            int lbar = Hc3_s[h].lbar;
            int lbar12 = Hc3_s[h].lbar_12;
            int lbar3 = Hc3_s[h].lbar_3;
            int i_1 = Hc3_s[h].i_1;
            int i_2 = Hc3_s[h].i_2;
            int i_3 = Hc3_s[h].i_3;
            int i_4 = Hc3_s[h].i_4;

            int A = lamb_i + i_1;
            int B = lamb_j + i_2;
            int C = lamb_k + lamb_3 + i_3;
            int D = lamb_l + lamb_4 + i_4;

            if (lbar > wave.lbar_max) {
              cout << "Wrong at Tpe_term::C3_term  lbar > wave.lbar_max"
                   << endl;
              exit(0);
            }
            int lbar_index = wave.lbar_vec[lbar][lbar12][lbar3];
            int klamb_index = wave.klamb_vec[lbar][A][B][C][D];
            if (klamb_index < 0) {
              cout << "Wrong at Tpe_term::C3_term klamb_index <0 " << endl;
              exit(0);
            }
            /*
            //cout<<"\t t_index : "<<t_index;

            */
            // double PFglbarS =
            // wave.PFKglbarS_vec[S_index][nlp_index][nl_index]
            //                                    [lbar_index][klamb_index];
            double PFglbarS =
                wave.PFKglbarS_quick(nlp_index, nl_index, A, B, C, D, S_index,
                                     lbar, lbar12, lbar3);
            /*double PFglbarS = 0.0;
            /*
            cout << "C3 term : ";
            cout << "\t nl_index : " << nl_index;
            cout << "\t nl_index : " << nl_index;
            cout << "\t nlp_index : " << nlp_index;
            cout << "\t lbar_index : " << lbar_index;
            cout << "\t lbar = " << lbar << "\t lba12 = " << lbar12
                 << "\t lbar3 =" << lbar3 << endl;
            cout << "\t klamb_index : " << klamb_index << endl;
            cout << "\t A : " << A << "\t B : " << B << "\t C : " << C
                 << "\t D : " << D << endl;
                 */
            // double PFglbarS = wave.PFKglbarS_quick(nlp_index, nl_index, A,
            // B, C,
            //                                       D, S_index, lbar_index);
            part3 += Gc3 * Ic3_val * Hc3_val * PFglbarS;
            /*
            cout<<"Gc1 = "<<Gc1<<endl;
            cout<<" \t PFglbarS = "<<PFglbarS<<endl;
            cout<<"  +sum val = "<<Gc1 * Ic1_val * Hc1_val * PFglbarS<<endl;
            */
            file << "Gc3 = " << Gc3 << "\t Ic3 = " << Ic3_val
                 << "\t Hc3 = " << Hc3_val;
            file << " \t PFglbarS = " << PFglbarS;
            file << "\t  +part3 val = " << Gc3 * Ic3_val * Hc3_val * PFglbarS
                 << endl;
          }
        }
      }
    }
  }

  result = phase_C3 * pf_tpe_c3 * part1 * part2 * part3;
  file << "\t --- part3 = " << part3 << " --- " << endl;
  file << "\t === C3_term : " << result << " === " << endl;
  file.close();
  return result;
}

double Tpe_term::C4_term2(const State_Jacobi &final_state,
                          const State_Jacobi &init_state) {
  double result = 0.0;

  // !!!! should n't have E conservation !!!!
  // energy conservation
  // if (final_state.E != init_state.E)
  //  return result;

  if ((final_state.J_2 != init_state.J_2) ||
      (final_state.T_2 != init_state.T_2))
    return result;
  // parity conservation
  int l12p = final_state.l12;
  int l12 = init_state.l12;
  int l3p = final_state.l3;
  int l3 = init_state.l3;

  int Par_Lp = l12p + l3p;
  int Par_L = l12 + l3;
  if ((Par_Lp % 2) != (Par_L % 2))
    return result;

  //
  // l state
  int l_index = l_vec[l12p][l12][l3p][l3];
  //
  int n12p = final_state.n12;
  int n3p = final_state.n3;
  int n12 = init_state.n12;
  int n3 = init_state.n3;
  int nlp_index = wave.nl_vec[n12p][n3p][l12p][l3p];
  int nl_index = wave.nl_vec[n12][n3][l12][l3];
  // sint S_index = 3; // s_1 = 2, s_2 = 2

  //
  int T12p = final_state.T12_2 / 2;
  int T12 = init_state.T12_2 / 2;
  int S12p = final_state.S12_2 / 2;
  int S12 = init_state.S12_2 / 2;

  // phase
  int phase_t = init_state.J12_2 + final_state.j3_2 + init_state.J_2 +
                init_state.T12_2 + 1 + init_state.T_2;
  phase_t = phase_t + final_state.l12 + final_state.l3 + init_state.l12 +
            init_state.l3;
  phase_t = phase_t / 2;
  int phase_C4 = phase(phase_t); // * phase(Par_L);
  //
  double part1_t, part1;
  part1_t = (final_state.J12_2 + 1) * (init_state.J12_2 + 1) *
            (final_state.j3_2 + 1) * (init_state.j3_2 + 1);
  part1 = std::sqrt(part1_t) * Hat_vec[T12p] * Hat_vec[T12] * Hat_vec[S12p] *
          Hat_vec[S12];
  // cout<<"Part1 = "<<part1<<endl;
  double part2 = 0.0;

  if (final_state.T_2 == 1) {
    part2 = T1_69J[T12p][T12];
  } else {
    part2 = T3_69J;
  }
  /*
  part2=sixJ.quick(final_state.T12_2, init_state.T12_2, 2, 1, 1,
  init_state.T_2); if(part2 == 0) return result; part2 *=
  ninJ.cal(1,1,2,1,1,2, final_state.T12_2, init_state.T12_2, 2);
  */
  // cout<<"Part2 = "<<part2<<endl;
  if (part2 == 0)
    return result;
  //
  // Gc1
  double part3 = 0;
  // t0
  int t02_min1 = std::abs(final_state.j3_2 - init_state.j3_2);
  int t02_max1 = (final_state.j3_2 + init_state.j3_2);
  int t02_min2 = std::abs(final_state.J12_2 - init_state.J12_2);
  int t02_max2 = (final_state.J12_2 + init_state.J12_2);

  int t02_min = std::max(t02_min1, t02_min2);
  int t02_max = std::min(t02_max1, t02_max2);
  if (t02_min > t02_max)
    return result;

  int t1_2_min1 = 2 * std::abs(l12p - l12);
  int t1_2_max1 = 2 * (l12p + l12);

  int t4_2_min1 = 2 * std::abs(l3p - l3);
  int t4_2_max1 = 2 * (l3p + l3);
  // cout<<"test point 1"<<endl;
  double Cs_0 = 0.0;
  for (int s_0 = 0; s_0 <= 2; s_0++) {
    // cout<<"test point 2 \t s_0 = "<<s_0<<endl;
    Cs_0 = (2 * s_0 + 1) * phase(s_0) * S12_9J[S12p][S12][s_0];
    // cout<<"Cs_0 = "<<Cs_0<<endl;
    if (Cs_0 == 0.0)
      continue;

    for (int t0_2 = t02_min; t0_2 <= t02_max; t0_2 = t0_2 + 2) {
      // cout<<"test point 3 \t t_02 = "<<t0_2<<endl;
      double G1 =
          sixJ.quick(final_state.J12_2, final_state.j3_2, init_state.J_2,
                     init_state.j3_2, init_state.J12_2, t0_2);
      if (G1 == 0.0)
        continue;
      G1 = G1 * phase(t0_2 / 2) * (t0_2 + 1);
      // cout<<"\t G1 = "<<G1<<endl;
      // t1

      int t1_2_min2 = std::abs(2 - t0_2);
      int t1_2_max2 = 2 + t0_2;
      int t1_2_min = std::max(t1_2_min1, t1_2_min2);
      int t1_2_max = std::min(t1_2_max1, t1_2_max2);

      int t4_2_min2 = t1_2_min2;
      int t4_2_max2 = t1_2_max2;
      int t4_2_min = std::max(t4_2_min1, t4_2_min2);
      int t4_2_max = std::min(t4_2_max1, t4_2_max2);

      if (t1_2_min > t1_2_max)
        continue;
      for (int t1_2 = t1_2_min; t1_2 <= t1_2_max; t1_2 = t1_2 + 2) {
        // cout<<"\t t1_2 = "<<t1_2<<endl;
        double G2 = ninJ.cal(2 * l12p, 2 * l12, t1_2, final_state.S12_2,
                             init_state.S12_2, 2 * s_0, final_state.J12_2,
                             init_state.J12_2, t0_2);
        if (G2 == 0.0)
          continue;
        G2 = G2 * phase(t1_2 / 2) * (t1_2 + 1);
        // cout<<"\t G2 = "<<G2<<endl;
        // t4
        if (t4_2_min > t4_2_max)
          continue;
        for (int t4_2 = t4_2_min; t4_2 <= t4_2_max; t4_2 = t4_2 + 2) {
          // cout<<"\t t4_2 = "<<t4_2<<endl;
          double G3 = ninJ.cal(2 * l3p, 2 * l3, t4_2, 1, 1, 2, final_state.j3_2,
                               init_state.j3_2, t0_2);
          if (G3 == 0.0)
            continue;
          G3 = G3 * phase(t4_2 / 2) * (t4_2 + 1);
          // cout<<"\t G3 = "<<G3<<endl;
          double Gc4 = G1 * G2 * G3;

          int t0 = t0_2 / 2;
          int t1 = t1_2 / 2;
          int t4 = t4_2 / 2;
          // int t_index = t014_vec[t0][t1][t4];
          int t_index = t014_vec2[l_index][t0][t1][t4];

          // cout<<"\t \t t_index = "<<t_index<<endl;
          // Ic4
          // cout<<"s_0 = "<<s_0<<"\t Cs_0 = "<<Cs_0<<endl;
          //#pragma omp parallel for reduction(+ : part3)
          for (int i = 0; i < Ic4_index[s_0][l_index].size(); i++) {

            // cout<<"test point 3"<<endl;
            double Ic4_val = Ic4_index[s_0][l_index][i].val;

            // cout<<"i : "<<i<<"\t Ic4_val = "<<Ic4_val<<endl;

            int lamb_i = Ic4_index[s_0][l_index][i].lamb_i;
            int lamb_j = Ic4_index[s_0][l_index][i].lamb_j;
            int lamb_k = Ic4_index[s_0][l_index][i].lamb_k;
            int lamb_l = Ic4_index[s_0][l_index][i].lamb_l;
            int lamb_3 = Ic4_index[s_0][l_index][i].lamb_3;
            int lamb_4 = Ic4_index[s_0][l_index][i].lamb_4;
            int s_1 = Ic4_index[s_0][l_index][i].s_1;
            int s_2 = Ic4_index[s_0][l_index][i].s_2;
            int S_index = s_1 / 2 + s_2;
            // cout<<"s_0 = "<<s_0<<"\t Cs_0 = "<<Cs_0<<endl;
            // if ( size_hc1 < 1)continue;
            // int size_hc4 = Hc4_state[s_0][l_index][i][t_index].size();
            vector<Hc_struct> Hc4_s;
            int size_hc4 = Hc4_cal(l_index, t0, t1, t4, s_0,
                                   Ic4_index[s_0][l_index][i], Hc4_s);
            // cout << size_hc4 << "\t Hc4_s size :" << Hc4_s.size() << endl;
            if (size_hc4 < 0)
              continue;
            // hc4

            for (int h = 0; h < size_hc4; h++) {
              double Hc4_val = Hc4_s[h].val;

              // cout<<"h : "<<h<<"\t Hc4_val = "<<Hc4_val<<endl;

              int lbar = Hc4_s[h].lbar;
              int lbar12 = Hc4_s[h].lbar_12;
              int lbar3 = Hc4_s[h].lbar_3;
              int i_1 = Hc4_s[h].i_1;
              int i_2 = Hc4_s[h].i_2;
              int i_3 = Hc4_s[h].i_3;
              int i_4 = Hc4_s[h].i_4;

              int A = lamb_i + i_1;
              int B = lamb_j + i_2;
              int C = lamb_k + lamb_3 + i_3;
              int D = lamb_l + lamb_4 + i_4;

              if (lbar > wave.lbar_max) {
                cout << "Wrong at Tpe_term::C4_term  lbar > wave.lbar_max"
                     << endl;
                exit(0);
              }
              int lbar_index = wave.lbar_vec[lbar][lbar12][lbar3];
              int klamb_index = wave.klamb_vec[lbar][A][B][C][D];
              if (klamb_index < 0) {
                cout << "Wrong at Tpe_term::C4_term klamb_index <0 " << endl;
                exit(0);
              }

              // cout<<"\t t_index : "<<t_index;
              /*
              cout << "C4 term : ";
              cout << "\t nl_index : " << nl_index;
              cout << "\t nlp_index : " << nlp_index;
              cout << "\t lbar_index : " << lbar_index;
              cout << "\t lbar = " << lbar << "\t lba12 = " << lbar12
                   << "\t lbar3 = " << lbar3 << endl;
              cout << "\t klamb_index : " << klamb_index << endl;
              cout << "\t A : " << A << "\t B : " << B << "\t C : " << C
                   << "\t D :" << D << endl;
                   */
              // double PFglbarS =
              // wave.PFKglbarS_vec[S_index][nlp_index][nl_index]
              //                                    [lbar_index][klamb_index];
              double PFglbarS =
                  wave.PFKglbarS_quick(nlp_index, nl_index, A, B, C, D, S_index,
                                       lbar, lbar12, lbar3);
              // double PFglbarS = 0.0;

              // double PFglbarS = wave.PFKglbarS_quick(nlp_index, nl_index,
              // A, B,
              //                                       C, D, S_index,
              //                                       lbar_index);

              part3 += Cs_0 * Gc4 * Ic4_val * Hc4_val * PFglbarS;
              /*
              cout<<"Gc1 = "<<Gc1<<endl;
              cout<<" \t PFglbarS = "<<PFglbarS<<endl;
              cout<<"  +sum val = "<<Gc1 * Ic1_val * Hc1_val *
              PFglbarS<<endl;
              */
            }
          }
        }
      }
    }
  }

  result = phase_C4 * pf_tpe_c4 * part1 * part2 * part3;
  /*
  cout << "C4  result : " << result << endl;
  cout << "\t phase_C4:" << phase_C4;
  cout << "\t pf_c4:" << pf_tpe_c4;
  cout << "\t part1:" << part1;
  cout << "\t part2:" << part2;
  cout << "\t part3:" << part3 << endl;

  /*
  cout<<"phase_C1 = "<<phase_C1<<endl;
  cout<<"pf_tpe_c1 = "<<pf_tpe_c1<<endl;
  cout<<"part1 = "<<part1<<endl;
  cout<<"part2 = "<<part2<<endl;
  cout<<"part3 = "<<part3<<endl;
  cout<<"result = "<<result<<endl;
  cout<<"PFglbarS = "<<wave.PFKglbarS_vec[3][0][0][13][121]<<endl;

  int lbar = 1;

  int A = wave.klamb_state[lbar][68].lamb12_p;
  int B = wave.klamb_state[lbar][68].lamb12;
  int C = wave.klamb_state[lbar][68].lamb3_p;
  int D = wave.klamb_state[lbar][68].lamb3;

  int klamb_index = wave.klamb_vec[lbar][A][B][C][D];
  cout<<"klamb : "<<klamb_index<<endl;
  cout<<"\t A : "<<A<<"\t B : "<<B<<"\t C : "<<C<<"\t D : "<<D<<endl;
    double PF = wave.PFKglbarS_vec_cal2(0,0,A,B,B,D,3,13);
  cout<<"\t PF = "<<PF<<endl;

  cout<<"\t lbar :"<<wave.lbar_state[13].lbar<<"\t lbar12
  :"<<wave.lbar_state[13].lbar12
    <<"\t lbar3 :"<<wave.lbar_state[13].lbar3<<endl;

  for(int i=0;i<wave.glbarS_vec[3][13][3].size();i++){
    //cout<<wave.glbarS2_vec[3][13][3][i]<<endl;
  }
  */

  return result;
}

void Tpe_term::build() {
  //
  // cout << "memory Ic1_index : " << this->Ic1_index.capacity() << endl;
  // cout << "memory Hc1_index : " << sizeof(this->Hc1_state) << endl;
  //
  int ch_size = jaco.channel.size();
  this->vec.resize(ch_size);
  this->vec1.resize(ch_size);
  this->vec3.resize(ch_size);
  this->vec4.resize(ch_size);
  Pgs_Bar pgs(ch_size, 30);
  // pgs.init()
  // cout << "Begin to build Tpe term :" << endl;
  for (int i = 0; i < ch_size; i++) {
    // pgs.PrintBar(i);
    int size = jaco.state[i].size();
    vec[i].resize(size);
    vec1[i].resize(size);
    vec3[i].resize(size);
    vec4[i].resize(size);
    // if(size<1)continue;
    // std::cout << "channel : " << i << endl;
    for (int x = 0; x < size; x++) {
      vec[i][x].resize(size);
      vec1[i][x].resize(size);
      vec3[i][x].resize(size);
      vec4[i][x].resize(size);
    }
#pragma omp parallel for schedule(dynamic, 1)
    for (int x = 0; x < size; x++) {
#pragma omp parallel for schedule(dynamic, 1)
      for (int y = 0; y <= x; y++) {
        int flag = -1;
        if (jaco.state[i][x].F > 0 && jaco.state[i][y].I > 0)
          flag = 1;
        // if (jaco.state[i][y].F > 0 && jaco.state[i][x].I > 0)flag=1;
        if (flag < 0)
          continue;
        // cout << x << "\t" << y << endl;
        // double val1 = this->C1_term(jaco.state[i][x], jaco.state[i][y]);
        double val1 = this->C1_term2(jaco.state[i][x], jaco.state[i][y]);
        // cout << "C1_term : " << val1 << "\t C1_term2 : " << val11 << endl;
        // double val3 = this->C3_term(jaco.state[i][x], jaco.state[i][y]);
        double val3 = this->C3_term2(jaco.state[i][x], jaco.state[i][y]);
        // cout << "C3_term : " << val3 << "\t C3_term2 : " << val33 << endl;
        // double val4 = this->C4_term(jaco.state[i][x], jaco.state[i][y]);
        double val4 = this->C4_term2(jaco.state[i][x], jaco.state[i][y]);
        // cout << "C4_term : " << val4 << "\t C4_term2 : " << val44 << endl;
        vec[i][x][y] = val1 + val3 + val4;
        vec[i][y][x] = val1 + val3 + val4;
        // vec[i][y][x] = val1 + val3 + val4;
        vec1[i][x][y] = val1;
        vec1[i][y][x] = val1;
        vec3[i][x][y] = val3;
        vec3[i][y][x] = val3;
        vec4[i][x][y] = val4;
        vec4[i][y][x] = val4;
      }
    }
  }
  // pgs.EndBar();
  // cout << "End to build Tpe term " << endl;
}

void Tpe_term::Jnlp_build(vector<vector<int>> E_JC) {
  int EJC_max = 0;
  int EJC_num = E_JC.size();
  for (int i = 0; i < EJC_num; i++) {
    if (E_JC[i][0] > EJC_max)
      EJC_max = E_JC[i][0];
    if (E_JC[i][1] > EJC_max)
      EJC_max = E_JC[i][1];
  }
  // calculate nlpnl_tpe;
  int n12_min = jaco.n12min;
  int l12_min = jaco.l12min;
  int n3_min = jaco.n3min;
  int l3_min = jaco.l3min;

  int n12_max = jaco.n12max;
  int l12_max = jaco.l12max;
  int n3_max = jaco.n3max;
  int l3_max = jaco.l3max;

  if (TpeCom.rank() == 0) {
    cout << "n12_min = " << n12_min << endl;
    cout << "l12_min = " << l12_min << endl;
    cout << "n3_min = " << n3_min << endl;
    cout << "l3_min = " << l3_min << endl;

    cout << "n12_max = " << n12_max << endl;
    cout << "l12_max = " << l12_max << endl;
    cout << "n3_max = " << n3_max << endl;
    cout << "l3_max = " << l3_max << endl;
  }

  // initial nl_vec and nl_state for TPE
  nl_vec_tpe.resize(n12_max + 1);
  for (int n12 = 0; n12 <= n12_max; n12++) {
    nl_vec_tpe[n12].resize(n3_max + 1);
    for (int n3 = 0; n3 <= n3_max; n3++) {
      nl_vec_tpe[n12][n3].resize(l12_max + 1);
      for (int l12 = 0; l12 <= l12_max; l12++) {
        nl_vec_tpe[n12][n3][l12].resize(l3_max + 1);
        for (int l3 = 0; l3 <= l3_max; l3++) {
          nl_vec_tpe[n12][n3][l12][l3] = -1;
        }
      }
    }
  }
  nl_struct nl_state_t;
  int index = 0;
  for (int n12 = n12_min; n12 <= n12_max; n12++) {
    for (int n3 = n3_min; n3 <= n3_max; n3++) {
      for (int l12 = l12_min; l12 <= l12_max; l12++) {
        for (int l3 = l3_min; l3 <= l3_max; l3++) {
          int E = 2 * (n12 + n3) + l12 + l3;
          if (E > EJC_max)
            continue;
          nl_vec_tpe[n12][n3][l12][l3] = index;
          nl_state_t.n12 = n12;
          nl_state_t.n3 = n3;
          nl_state_t.l12 = l12;
          nl_state_t.l3 = l3;
          nl_state_tpe.push_back(nl_state_t);
          index++;
        }
      }
    }
  }
  // calculate nlpnl_state
  nlpnl_struct nlpnl_state_t;
  int index_nlpnl = 0;
  int nl_size = nl_state_tpe.size();
  nlpnl_vec_tpe.resize(nl_size);
  nlpnl_state_tpe.clear();
  for (int i = 0; i < nl_size; i++) {
    nlpnl_vec_tpe[i].resize(nl_size);
    int Par_p = this->phase(nl_state_tpe[i].l12 + nl_state_tpe[i].l3);
    int E_p = 2 * (nl_state_tpe[i].n12 + nl_state_tpe[i].n3) +
              nl_state_tpe[i].l12 + nl_state_tpe[i].l3;
    vector<int> E_p_pos;
    for (int k1 = 0; k1 < E_JC.size(); k1++) {
      if (E_p == E_JC[k1][0]) {
        E_p_pos.push_back(k1);
      }
    }
    if (E_p_pos.size() == 0)
      continue;
    for (int j = 0; j < nl_size; j++) {
      nlpnl_vec_tpe[i][j] = -1;

      int Par = this->phase(nl_state_tpe[j].l12 + nl_state_tpe[j].l3);
      int E = 2 * (nl_state_tpe[j].n12 + nl_state_tpe[j].n3) +
              nl_state_tpe[j].l12 + nl_state_tpe[j].l3;

      int E_JC_flag = -1;
      for (int k2 = 0; k2 < E_p_pos.size(); k2++) {
        int a = E_p_pos[k2];
        if (E == E_JC[a][1]) {
          E_JC_flag = 1;
          break;
        }
      }
      if (E_JC_flag == 1 && Par_p == Par) {
        if (E <= jaco.Emax_I && E_p <= jaco.Emax_F) {
          nlpnl_state_t.nl_p = i;
          nlpnl_state_t.nl = j;
          nlpnl_state_tpe.push_back(nlpnl_state_t);
          nlpnl_vec_tpe[i][j] = index_nlpnl;
          index_nlpnl++;
        }
      }
    }
  }
  // calculate nlpnl_Wav2Tpe_vec

  if (nlpnl_state_tpe.size() > wave.nlpnl_state.size()) {
    if (TpeCom.rank() == 0) {
      cout << "Wrong at Tpe_term::Jnlp_build  nlpnl_state_tpe.size() > "
              "wave.nlpnl_state.size()"
           << endl;
      cout << "Tpe nl_size = " << nl_size
           << "\t Wave nl_size = " << wave.nl_state.size() << endl;
      cout << "\t nlpnl_state_tpe = " << nlpnl_state_tpe.size()
           << "\t wave.nlpnl_state.size = " << wave.nlpnl_state.size() << endl;
      cout << "jaco.Emax_F = " << jaco.Emax_F
           << "\t jaco.Emax_I = " << jaco.Emax_I << endl;
    }
    exit(0);
  }
  int size_nlpnl_wave = wave.nlpnl_state.size();
  this->nlpnl_Wav2Tpe_vec.resize(size_nlpnl_wave);
  for (int i = 0; i < wave.nlpnl_state.size(); i++) {
    nlpnl_Wav2Tpe_vec[i] = -1;
    int nl_w = wave.nlpnl_state[i].nl;
    int nlp_w = wave.nlpnl_state[i].nl_p;

    int n12_w = wave.nl_state[nl_w].n12;
    int n3_w = wave.nl_state[nl_w].n3;
    int l12_w = wave.nl_state[nl_w].l12;
    int l3_w = wave.nl_state[nl_w].l3;

    int n12p_w = wave.nl_state[nlp_w].n12;
    int n3p_w = wave.nl_state[nlp_w].n3;
    int l12p_w = wave.nl_state[nlp_w].l12;
    int l3p_w = wave.nl_state[nlp_w].l3;
    for (int j = 0; j < nlpnl_state_tpe.size(); j++) {
      int nl = nlpnl_state_tpe[j].nl;
      int nl_p = nlpnl_state_tpe[j].nl_p;

      int n12 = nl_state_tpe[nl].n12;
      int n3 = nl_state_tpe[nl].n3;
      int l12 = nl_state_tpe[nl].l12;
      int l3 = nl_state_tpe[nl].l3;

      int n12p = nl_state_tpe[nl_p].n12;
      int n3p = nl_state_tpe[nl_p].n3;
      int l12p = nl_state_tpe[nl_p].l12;
      int l3p = nl_state_tpe[nl_p].l3;
      if (n12_w != n12 || n3_w != n3)
        continue;
      if (l12_w != l12 || l3_w != l3)
        continue;
      if (n12p_w != n12p || n3p_w != n3p)
        continue;
      if (l12p_w != l12p || l3p_w != l3p)
        continue;
      nlpnl_Wav2Tpe_vec[i] = j;
    }
  }
  int check_nlpnl_Wav2Tpe_vec = 0;
  for (int i = 0; i < nlpnl_Wav2Tpe_vec.size(); i++) {
    int j = nlpnl_Wav2Tpe_vec[i];
    if (j >= 0)
      check_nlpnl_Wav2Tpe_vec++;
  }

  int size_nlpnl_tpe = nlpnl_state_tpe.size();
  // cout<<"nlpnl_state_tpe.size() = "<<size_nlpnl_tpe<<"\t Rank =
  // "<<TpeCom.rank()<<endl;

  if (check_nlpnl_Wav2Tpe_vec != size_nlpnl_tpe) {
    if (TpeCom.rank() == 0) {
      std::ofstream file_nl_w;
      file_nl_w.open("data/nl_state_wave.dat");
      file_nl_w << "i\t n12\t n3\t l12\t l3\t ?" << endl;
      for (int i = 0; i < wave.nl_state.size(); i++) {
        file_nl_w << i << "\t" << wave.nl_state[i].n12;
        file_nl_w << "\t" << wave.nl_state[i].n3;
        file_nl_w << "\t" << wave.nl_state[i].l12;
        file_nl_w << "\t" << wave.nl_state[i].l3 << endl;
      }
      file_nl_w.close();
      std::ofstream file_nlpnl_w;
      file_nlpnl_w.open("data/nlpnl_state_wave.dat");
      file_nlpnl_w << "No.\t nl'\t nl" << endl;
      for (int i = 0; i < wave.nlpnl_state.size(); i++) {
        file_nlpnl_w << i << "\t" << wave.nlpnl_state[i].nl_p << "\t"
                     << wave.nlpnl_state[i].nl << endl;
      }
      file_nlpnl_w.close();
    }
    cout << "Wrong at Tpe_term::Jnlp_build 2 check_nlpnl_Wav2Tpe_vec != "
            "nlpnl_state_tpe.size() Please check nlpnl_state_wave.dat Vs "
            "nlpnl_state_tpe.dat and nl_state_tpe.dat Vs nl_state_wave.dat"
         << endl;
    cout << "check_nlpnl_Wav2Tpe_vec = " << check_nlpnl_Wav2Tpe_vec
         << "\t nlpnl_state_tpe.size() = " << nlpnl_state_tpe.size() << endl;
    exit(0);
  }

  // calculate Jnlp, the configuration of Jacobi initial and final state
  this->nlpnl_size = nlpnl_state_tpe.size();
  this->Jnlp.resize(nlpnl_size);
  int channel_size = jaco.state.size();
  for (int n = 0; n < nlpnl_size; n++) {
    int nl = nlpnl_state_tpe[n].nl;
    int nl_p = nlpnl_state_tpe[n].nl_p;

    int n12 = nl_state_tpe[nl].n12;
    int n3 = nl_state_tpe[nl].n3;
    int l12 = nl_state_tpe[nl].l12;
    int l3 = nl_state_tpe[nl].l3;

    int n12p = nl_state_tpe[nl_p].n12;
    int n3p = nl_state_tpe[nl_p].n3;
    int l12p = nl_state_tpe[nl_p].l12;
    int l3p = nl_state_tpe[nl_p].l3;

    Jnlp[n].resize(channel_size);
    for (int ch = 0; ch < channel_size; ch++) {
      int index_jaco = 0;
      for (int i = 0; i < jaco.state[ch].size(); i++) {
        int n12_i = jaco.state[ch][i].n12;
        int n3_i = jaco.state[ch][i].n3;
        int l12_i = jaco.state[ch][i].l12;
        int l3_i = jaco.state[ch][i].l3;

        if (n12_i != n12)
          continue;
        if (n3_i != n3)
          continue;
        if (l12_i != l12)
          continue;
        if (l3_i != l3)
          continue;
        for (int f = 0; f < jaco.state[ch].size(); f++) {
          int flag = -1;
          if (jaco.state[ch][f].F > 0 && jaco.state[ch][i].I > 0)
            flag = 1;
          // if (jaco.state[i][y].F > 0 && jaco.state[i][x].I > 0)flag=1;
          if (flag < 0)
            continue;
          int n12_f = jaco.state[ch][f].n12;
          int n3_f = jaco.state[ch][f].n3;
          int l12_f = jaco.state[ch][f].l12;
          int l3_f = jaco.state[ch][f].l3;
          if (n12_f != n12p)
            continue;
          if (n3_f != n3p)
            continue;
          if (l12_f != l12p)
            continue;
          if (l3_f != l3p)
            continue;
          Jaco_nlpnl_struct Jnlp_t;
          Jnlp_t.i = i;
          Jnlp_t.f = f;
          Jnlp[n][ch].push_back(Jnlp_t);
        }
      }
    }
  }
  if (TpeCom.rank() == 0) {
    std::ofstream file_nl;
    file_nl.open("data/nl_state_tpe.dat");
    file_nl << "i\t n12\t n3\t l12\t l3\t ?" << endl;
    for (int i = 0; i < nl_state_tpe.size(); i++) {
      file_nl << i << "\t" << nl_state_tpe[i].n12;
      file_nl << "\t" << nl_state_tpe[i].n3;
      file_nl << "\t" << nl_state_tpe[i].l12;
      file_nl << "\t" << nl_state_tpe[i].l3 << endl;
    }
    file_nl.close();
    std::ofstream file_nlpnl;
    file_nlpnl.open("data/nlpnl_state_tpe.dat");
    file_nlpnl << "No.\t nl'\t nl" << endl;
    for (int i = 0; i < nlpnl_state_tpe.size(); i++) {
      file_nlpnl << i << "\t" << nlpnl_state_tpe[i].nl_p << "\t"
                 << nlpnl_state_tpe[i].nl << endl;
    }
    file_nlpnl.close();

    std::ofstream file_Jnlp;
    file_Jnlp.open("data/Jnlp.dat");
    for (int ch = 0; ch < channel_size; ch++) {
      file_Jnlp << " == channel : " << ch << " == " << endl;
      for (int n = 0; n < nlpnl_size; n++) {
        file_Jnlp << " \t nlpnl index : " << n << endl;
        file_Jnlp << "No.\t final_index\t init_index" << endl;
        for (int i = 0; i < Jnlp[n][ch].size(); i++) {
          file_Jnlp << i << "\t" << Jnlp[n][ch][i].f << "\t" << Jnlp[n][ch][i].i
                    << endl;
        }
      }
    }
    file_Jnlp.close();
  }
  /*
  std::ofstream file_Jnlp;
  file_Jnlp.open("data/Jnlp.dat");
  for (int n = 0; n < nlpnl_size; n++) {
    file_Jnlp << " \t nlpnl index : " << n << endl;
    for (int ch = 0; ch < channel_size; ch++) {
      file_Jnlp << " == channel : " << ch << " == " << endl;

      file_Jnlp << "No.\t final_index\t init_index" << endl;
      for (int i = 0; i < Jnlp[n][ch].size(); i++) {
        file_Jnlp << i << "\t" << Jnlp[n][ch][i].f << "\t" << Jnlp[n][ch][i].i
                  << endl;
      }
    }
  }
  file_Jnlp.close();
  */
  // Finde & Delete init_index <-> finial_index in same channel
  for (int ch = 0; ch < channel_size; ch++) {
    for (int a = 0; a < nlpnl_size; a++) {
      if (Jnlp[a][ch].size() == 0)
        continue;
      int nl_a = nlpnl_state_tpe[a].nl;
      int nlp_a = nlpnl_state_tpe[a].nl_p;
      for (int ia = 0; ia < Jnlp[a][ch].size(); ia++) {
        int A_init = Jnlp[a][ch][ia].i;
        int A_final = Jnlp[a][ch][ia].f;

        for (int b = a; b < nlpnl_size; b++) {
          if (Jnlp[b][ch].size() == 0)
            continue;
          int nl_b = nlpnl_state_tpe[b].nl;
          int nlp_b = nlpnl_state_tpe[b].nl_p;
          if (nl_b != nlp_a || nlp_b != nl_a)
            continue;
          auto it = Jnlp[b][ch].begin();
          while (it != Jnlp[b][ch].end()) {
            int B_init = it->i;
            int B_final = it->f;
            if (A_init == B_final && A_final == B_init && B_init != B_final) {
              it = Jnlp[b][ch].erase(it);
            } else {
              it++;
            }
          }
        }
      }
    }
  }
  if (TpeCom.rank() == 0) {
    std::ofstream file_Jnlp;
    file_Jnlp.open("data/Jnlp_delete.dat");
    file_Jnlp << "MPI task : proc(num)" << endl;
    int mpi_size_c = TpeCom.size();
    vector<int> mpi_task_vec(mpi_size_c);
    for (int n = 0; n < nlpnl_size; n++) {
      int num = 0;
      for (int ch = 0; ch < channel_size; ch++) {
        num += Jnlp[n][ch].size();
      }
      int my_rank_c = n % mpi_size_c;
      mpi_task_vec[my_rank_c] += num;
      file_Jnlp << std::setw(3) << n << "(" << std::setw(3) << num << ")"
                << "\t";
      if (n % mpi_size_c == (mpi_size_c - 1))
        file_Jnlp << endl;
    }
    file_Jnlp << endl;
    for (int i = 0; i < mpi_size_c; i++) {
      file_Jnlp << mpi_task_vec[i] << "\t\t";
    }
    file_Jnlp << endl;
    file_Jnlp << "~~~~~~~~~~~~~~~~" << endl;
    for (int n = 0; n < nlpnl_size; n++) {
      file_Jnlp << " \t ======  nlpnl index : " << n << " ======" << endl;
      for (int ch = 0; ch < channel_size; ch++) {
        file_Jnlp << " -- channel : " << ch << " -- " << endl;
        file_Jnlp << "No.\t final_index\t init_index" << endl;
        for (int i = 0; i < Jnlp[n][ch].size(); i++) {
          file_Jnlp << i << "\t" << Jnlp[n][ch][i].f << "\t" << Jnlp[n][ch][i].i
                    << endl;
        }
      }
    }
    file_Jnlp.close();
  }
}

void Tpe_term::get_Llbar_info() {
  int size_l = l_state.size();
  int lbar_max_t = 0;
  for (int s_0 = 0; s_0 <= 2; s_0++) {
    for (int l = 0; l < size_l; l++) {

      for (int i = 0; i < Ic4_index[s_0][l].size(); i++) {
        int q_1 = Ic4_index[s_0][l][i].q_1;
        int q_2 = Ic4_index[s_0][l][i].q_2;
        int q_3 = Ic4_index[s_0][l][i].q_3;
        int q_4 = Ic4_index[s_0][l][i].q_4;
        int s_3 = Ic4_index[s_0][l][i].s_3;
        int s_4 = Ic4_index[s_0][l][i].s_4;
        int lamb_1 = Ic4_index[s_0][l][i].lamb_1;
        int size_t = t014_state2[l].size();

        int lbar_min1 = std::abs(q_1 - q_2);
        int lbar_max1 = q_1 + q_2;
        int lbar_min2 = std::abs(q_3 - q_4);
        int lbar_max2 = q_3 + q_4;

        int lbar_minA = std::max(lbar_min1, lbar_min2);
        int lbar_maxA = std::min(lbar_max1, lbar_max2);

        for (int t = 0; t < size_t; t++) {
          int t0 = t014_state2[l][t].t_0;
          int t1 = t014_state2[l][t].t_1;
          int t4 = t014_state2[l][t].t_4;

          int lbar_min3 = std::abs(s_3 - t0);
          int lbar_max3 = s_3 + t0;
          int lbar_min4 = std::abs(lamb_1 - t1);
          int lbar_max4 = lamb_1 + t1;
          int lbar_min5 = std::abs(s_4 - t4);
          int lbar_max5 = s_4 + t4;

          int lbar_minB = std::max(lbar_min3, lbar_min4);
          int lbar_minC = std::max(lbar_minB, lbar_min5);
          int lbar_maxB = std::min(lbar_max3, lbar_max4);
          int lbar_maxC = std::min(lbar_maxB, lbar_max5);

          int lbar_min = std::max(lbar_minA, lbar_minC);
          int lbar_max = std::min(lbar_maxA, lbar_maxC);

          if (lbar_max > lbar_max_t)
            lbar_max_t = lbar_max;
        }
      }
    }
  }
  this->lbar123_max = lbar_max_t;
  this->Ic4_lbar_max = lbar_max_t;
  if (TpeCom.rank() == 0)
    cout << " Ic4 lbar max = " << lbar123_max << endl;

  cout << "Start to Build lbar_stat in TPE" << endl;
  int lbar12_max = lbar123_max;
  int lbar3_max = lbar123_max;
  int index = 0;
  lbar_struct_tpe lbar_state_t;
  lbar_state.clear();
  lbar_vec.resize(lbar123_max + 1);
  for (int l1 = 0; l1 <= lbar123_max; l1++) {
    lbar_vec[l1].resize(lbar12_max + 1);
    for (int l2 = 0; l2 <= lbar12_max; l2++) {
      lbar_vec[l1][l2].resize(lbar3_max + 1);
      for (int l3 = 0; l3 <= lbar3_max; l3++) {
        lbar_vec[l1][l2][l3] = index;
        lbar_state_t.lbar = l1;
        lbar_state_t.lbar12 = l2;
        lbar_state_t.lbar3 = l3;
        lbar_state.push_back(lbar_state_t);
        index++;
      }
    }
  }

  cout << "Start to Build Llbar_Ic_Reduced in TPE" << endl;
  int size_lbar = lbar_state.size();

  vector<vector<int>> Ic1_lbar_index_flag(size_l);
  vector<vector<int>> Ic3_lbar_index_flag(size_l);

  for (int l = 0; l < size_l; l++) {
    Ic1_lbar_index_flag[l].resize(size_lbar);
    Ic3_lbar_index_flag[l].resize(size_lbar);

    for (int i = 0; i < size_lbar; i++) {
      Ic1_lbar_index_flag[l][i] = -1;
      Ic3_lbar_index_flag[l][i] = -1;
    }

#pragma omp parallel for schedule(dynamic, 1)
    for (int i = 0; i < Ic1_index[l].size(); i++) {
      int q_1 = Ic1_index[l][i].q_1;
      int q_2 = Ic1_index[l][i].q_2;
      int q_3 = Ic1_index[l][i].q_3;
      int q_4 = Ic1_index[l][i].q_4;
      int lamb_2 = Ic1_index[l][i].lamb_2;
      int lamb_12 = Ic1_index[l][i].lamb_12;
      int lamb_1 = Ic1_index[l][i].lamb_1;
      int size_t = t014_state2[l].size();

      int lbar_min1 = std::abs(q_1 - q_2);
      int lbar_max1 = q_1 + q_2;
      int lbar_min2 = std::abs(q_3 - q_4);
      int lbar_max2 = q_3 + q_4;

      int lbar_minA = std::max(lbar_min1, lbar_min2);
      int lbar_maxA = std::min(lbar_max1, lbar_max2);

      for (int t = 0; t < size_t; t++) {
        int t0 = t014_state2[l][t].t_0;
        int t1 = t014_state2[l][t].t_1;
        int t4 = t014_state2[l][t].t_4;

        int lbar_min3 = std::abs(lamb_2 - t0);
        int lbar_max3 = lamb_2 + t0;
        int lbar_min4 = std::abs(lamb_1 - t1);
        int lbar_max4 = lamb_1 + t1;
        int lbar_min5 = std::abs(lamb_12 - t4);
        int lbar_max5 = lamb_12 + t4;

        int lbar_minB = std::max(lbar_min3, lbar_min4);
        int lbar_minC = std::max(lbar_minB, lbar_min5);
        int lbar_maxB = std::min(lbar_max3, lbar_max4);
        int lbar_maxC = std::min(lbar_maxB, lbar_max5);

        int lbar_min = std::max(lbar_minA, lbar_minC);
        int lbar_max = std::min(lbar_maxA, lbar_maxC);

        for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
          for (int i_1 = 0; i_1 <= lbar; i_1++) {
            int i_2 = lbar - i_1;
            int lbar12_minA = std::abs(i_1 - q_1);
            int lbar12_maxA = i_1 + q_1;
            int lbar12_minB = std::abs(i_2 - q_2);
            int lbar12_maxB = i_2 + q_2;
            int lbar12_min = std::max(lbar12_minA, lbar12_minB);
            int lbar12_max = std::min(lbar12_maxA, lbar12_maxB);
            for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
              for (int i_3 = 0; i_3 <= lbar; i_3++) {
                int i_4 = lbar - i_3;
                int lbar3_minA = std::abs(i_3 - q_3);
                int lbar3_maxA = i_3 + q_3;
                int lbar3_minB = std::abs(i_4 - q_4);
                int lbar3_maxB = i_4 + q_4;
                int lbar3_min = std::max(lbar3_minA, lbar3_minB);
                int lbar3_max = std::min(lbar3_maxA, lbar3_maxB);
                for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
                  int lbar_index = lbar_vec[lbar][lbar12][lbar3];
                  Ic1_lbar_index_flag[l][lbar_index] = 1;
                }
              }
            }
          }
        }
      }
    }

#pragma omp parallel for schedule(dynamic, 1)
    for (int i = 0; i < Ic3_index[l].size(); i++) {
      int q_1 = Ic3_index[l][i].q_1;
      int q_2 = Ic3_index[l][i].q_2;
      int q_3 = Ic3_index[l][i].q_3;
      int q_4 = Ic3_index[l][i].q_4;
      int s_3 = Ic3_index[l][i].s_3;
      int s_4 = Ic3_index[l][i].s_4;
      int lamb_1 = Ic3_index[l][i].lamb_1;
      int size_t = t014_state2[l].size();

      int lbar_min1 = std::abs(q_1 - q_2);
      int lbar_max1 = q_1 + q_2;
      int lbar_min2 = std::abs(q_3 - q_4);
      int lbar_max2 = q_3 + q_4;

      int lbar_minA = std::max(lbar_min1, lbar_min2);
      int lbar_maxA = std::min(lbar_max1, lbar_max2);

      for (int t = 0; t < size_t; t++) {
        int t0 = t014_state2[l][t].t_0;
        int t1 = t014_state2[l][t].t_1;
        int t4 = t014_state2[l][t].t_4;

        int lbar_min3 = std::abs(s_3 - t0);
        int lbar_max3 = s_3 + t0;
        int lbar_min4 = std::abs(lamb_1 - t1);
        int lbar_max4 = lamb_1 + t1;
        int lbar_min5 = std::abs(s_4 - t4);
        int lbar_max5 = s_4 + t4;

        int lbar_minB = std::max(lbar_min3, lbar_min4);
        int lbar_minC = std::max(lbar_minB, lbar_min5);
        int lbar_maxB = std::min(lbar_max3, lbar_max4);
        int lbar_maxC = std::min(lbar_maxB, lbar_max5);

        int lbar_min = std::max(lbar_minA, lbar_minC);
        int lbar_max = std::min(lbar_maxA, lbar_maxC);

        for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
          for (int i_1 = 0; i_1 <= lbar; i_1++) {
            int i_2 = lbar - i_1;
            int lbar12_minA = std::abs(i_1 - q_1);
            int lbar12_maxA = i_1 + q_1;
            int lbar12_minB = std::abs(i_2 - q_2);
            int lbar12_maxB = i_2 + q_2;
            int lbar12_min = std::max(lbar12_minA, lbar12_minB);
            int lbar12_max = std::min(lbar12_maxA, lbar12_maxB);
            for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
              for (int i_3 = 0; i_3 <= lbar; i_3++) {
                int i_4 = lbar - i_3;
                int lbar3_minA = std::abs(i_3 - q_3);
                int lbar3_maxA = i_3 + q_3;
                int lbar3_minB = std::abs(i_4 - q_4);
                int lbar3_maxB = i_4 + q_4;
                int lbar3_min = std::max(lbar3_minA, lbar3_minB);
                int lbar3_max = std::min(lbar3_maxA, lbar3_maxB);
                for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
                  int lbar_index = lbar_vec[lbar][lbar12][lbar3];
                  Ic3_lbar_index_flag[l][lbar_index] = 1;
                }
              }
            }
          }
        }
      }
    }
  }

  //
  vector<vector<vector<int>>> Ic4_lbar_index_flag(3);
  cout << "Start to build Ic4" << endl;

  for (int s_0 = 0; s_0 <= 2; s_0++) {
    Ic4_lbar_index_flag[s_0].resize(size_l);
    for (int l = 0; l < Ic4_index[s_0].size(); l++) {
      Ic4_lbar_index_flag[s_0][l].resize(size_lbar);

      for (int i = 0; i < size_lbar; i++) {
        Ic4_lbar_index_flag[s_0][l][i] = -1;
      }
#pragma omp parallel for schedule(dynamic, 1)
      for (int i = 0; i < Ic4_index[s_0][l].size(); i++) {
        int q_1 = Ic4_index[s_0][l][i].q_1;
        int q_2 = Ic4_index[s_0][l][i].q_2;
        int q_3 = Ic4_index[s_0][l][i].q_3;
        int q_4 = Ic4_index[s_0][l][i].q_4;
        int s_3 = Ic4_index[s_0][l][i].s_3;
        int s_4 = Ic4_index[s_0][l][i].s_4;
        int lamb_1 = Ic4_index[s_0][l][i].lamb_1;
        int size_t = t014_state2[l].size();

        int lbar_min1 = std::abs(q_1 - q_2);
        int lbar_max1 = q_1 + q_2;
        int lbar_min2 = std::abs(q_3 - q_4);
        int lbar_max2 = q_3 + q_4;

        int lbar_minA = std::max(lbar_min1, lbar_min2);
        int lbar_maxA = std::min(lbar_max1, lbar_max2);

        for (int t = 0; t < size_t; t++) {
          int t0 = t014_state2[l][t].t_0;
          int t1 = t014_state2[l][t].t_1;
          int t4 = t014_state2[l][t].t_4;

          int lbar_min3 = std::abs(s_3 - t0);
          int lbar_max3 = s_3 + t0;
          int lbar_min4 = std::abs(lamb_1 - t1);
          int lbar_max4 = lamb_1 + t1;
          int lbar_min5 = std::abs(s_4 - t4);
          int lbar_max5 = s_4 + t4;

          int lbar_minB = std::max(lbar_min3, lbar_min4);
          int lbar_minC = std::max(lbar_minB, lbar_min5);
          int lbar_maxB = std::min(lbar_max3, lbar_max4);
          int lbar_maxC = std::min(lbar_maxB, lbar_max5);

          int lbar_min = std::max(lbar_minA, lbar_minC);
          int lbar_max = std::min(lbar_maxA, lbar_maxC);

          for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
            for (int i_1 = 0; i_1 <= lbar; i_1++) {
              int i_2 = lbar - i_1;
              int lbar12_minA = std::abs(i_1 - q_1);
              int lbar12_maxA = i_1 + q_1;
              int lbar12_minB = std::abs(i_2 - q_2);
              int lbar12_maxB = i_2 + q_2;
              int lbar12_min = std::max(lbar12_minA, lbar12_minB);
              int lbar12_max = std::min(lbar12_maxA, lbar12_maxB);
              for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
                for (int i_3 = 0; i_3 <= lbar; i_3++) {
                  int i_4 = lbar - i_3;
                  int lbar3_minA = std::abs(i_3 - q_3);
                  int lbar3_maxA = i_3 + q_3;
                  int lbar3_minB = std::abs(i_4 - q_4);
                  int lbar3_maxB = i_4 + q_4;
                  int lbar3_min = std::max(lbar3_minA, lbar3_minB);
                  int lbar3_max = std::min(lbar3_maxA, lbar3_maxB);
                  for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
                    int lbar_index = lbar_vec[lbar][lbar12][lbar3];
                    Ic4_lbar_index_flag[s_0][l][lbar_index] = 1;
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  //
  Llbar_Ic_Reduced.resize(size_l);
  Llbar_Ic_Red_vec.resize(size_l);
  for (int l = 0; l < size_l; l++) {
    Llbar_Ic_Red_vec[l].resize(size_lbar);
    for (int lb_i = 0; lb_i < size_lbar; lb_i++)
      Llbar_Ic_Red_vec[l][lb_i] = -1;
    int index = 0;
    for (int lb_i = 0; lb_i < size_lbar; lb_i++) {
      int flag = -1;

      if (Ic1_lbar_index_flag[l][lb_i] > 0)
        flag = 1;
      if (Ic3_lbar_index_flag[l][lb_i] > 0)
        flag = 1;
      if (flag < 0) {
        for (int s_0 = 0; s_0 <= 2; s_0++) {
          if (Ic4_lbar_index_flag[s_0][l][lb_i] > 0)
            flag = 1;
        }
      }
      if (flag < 0)
        continue;
      Llbar_Ic_Reduced[l].push_back(lb_i);
      Llbar_Ic_Red_vec[l][lb_i] = index;
      index++;
    }
  }

  // cout << " Ic4 lbar max = " << lbar123_max
  //     << "\t Ic4 index all size = " << index << endl;
}

void Tpe_term::get_Llbar_info(vector<lbar_struct_tpe> &lb_s,
                              vector<vector<vector<int>>> &lb_vec,
                              int &lbar_max_tpe,
                              vector<vector<int>> &Llbar_Ic_R,
                              vector<vector<int>> &Llbar_Ic_R_vec) {
  int size_l = l_state.size();
  int lbar_max_t = 0;
  for (int s_0 = 0; s_0 <= 2; s_0++) {
    for (int l = 0; l < size_l; l++) {
      int i_size = Ic4_index[s_0][l].size();
      // cout << " ### -- ## i_size = " << i_size << endl;
      for (int i = 0; i < Ic4_index[s_0][l].size(); i++) {
        int q_1 = Ic4_index[s_0][l][i].q_1;
        int q_2 = Ic4_index[s_0][l][i].q_2;
        int q_3 = Ic4_index[s_0][l][i].q_3;
        int q_4 = Ic4_index[s_0][l][i].q_4;
        int s_3 = Ic4_index[s_0][l][i].s_3;
        int s_4 = Ic4_index[s_0][l][i].s_4;
        int lamb_1 = Ic4_index[s_0][l][i].lamb_1;
        int size_t = t014_state2[l].size();

        int lbar_min1 = std::abs(q_1 - q_2);
        int lbar_max1 = q_1 + q_2;
        int lbar_min2 = std::abs(q_3 - q_4);
        int lbar_max2 = q_3 + q_4;

        int lbar_minA = std::max(lbar_min1, lbar_min2);
        int lbar_maxA = std::min(lbar_max1, lbar_max2);

        for (int t = 0; t < size_t; t++) {
          int t0 = t014_state2[l][t].t_0;
          int t1 = t014_state2[l][t].t_1;
          int t4 = t014_state2[l][t].t_4;

          int lbar_min3 = std::abs(s_3 - t0);
          int lbar_max3 = s_3 + t0;
          int lbar_min4 = std::abs(lamb_1 - t1);
          int lbar_max4 = lamb_1 + t1;
          int lbar_min5 = std::abs(s_4 - t4);
          int lbar_max5 = s_4 + t4;

          int lbar_minB = std::max(lbar_min3, lbar_min4);
          int lbar_minC = std::max(lbar_minB, lbar_min5);
          int lbar_maxB = std::min(lbar_max3, lbar_max4);
          int lbar_maxC = std::min(lbar_maxB, lbar_max5);

          int lbar_min = std::max(lbar_minA, lbar_minC);
          int lbar_max = std::min(lbar_maxA, lbar_maxC);

          if (lbar_max > lbar_max_t)
            lbar_max_t = lbar_max;
        }
      }
    }
  }
  lbar_max_tpe = lbar_max_t;
  // this->lbar123_max = lbar_max_t;
  // this->Ic4_lbar_max = lbar_max_t;
  cout << " ## Good 1 " << endl;
  if (TpeCom.rank() == 0)
    cout << " Ic4 lbar max = " << lbar_max_tpe << endl;

  cout << "Start to Build lbar_stat in TPE" << endl;
  int lbar12_max = lbar_max_tpe;
  int lbar3_max = lbar_max_tpe;
  int index = 0;
  lbar_struct_tpe lbar_s_t;
  lb_s.clear();
  lb_vec.resize(lbar_max_tpe + 1);
  for (int l1 = 0; l1 <= lbar_max_tpe; l1++) {
    lb_vec[l1].resize(lbar12_max + 1);
    for (int l2 = 0; l2 <= lbar12_max; l2++) {
      lb_vec[l1][l2].resize(lbar3_max + 1);
      for (int l3 = 0; l3 <= lbar3_max; l3++) {
        lb_vec[l1][l2][l3] = index;
        lbar_s_t.lbar = l1;
        lbar_s_t.lbar12 = l2;
        lbar_s_t.lbar3 = l3;
        lb_s.push_back(lbar_s_t);
        index++;
      }
    }
  }

  cout << "Start to Build Llbar_Ic_Reduced in TPE" << endl;
  int size_lbar = lb_s.size();
  // cout << " ## Good 2 \t size_lbar = " << size_lbar << "\t size_l = " <<
  // size_l
  //<< endl;
  vector<vector<int>> Ic1_lbar_index_flag(size_l);
  vector<vector<int>> Ic3_lbar_index_flag(size_l);

  vector<int> lbar_flag(size_lbar, -1);
  for (int l = 0; l < size_l; l++) {
    Ic1_lbar_index_flag[l].resize(size_lbar);
    Ic3_lbar_index_flag[l].resize(size_lbar);

    for (int i = 0; i < size_lbar; i++) {
      Ic1_lbar_index_flag[l][i] = -1;
      Ic3_lbar_index_flag[l][i] = -1;
    }

#pragma omp parallel for schedule(dynamic, 1)
    for (int i = 0; i < Ic1_index[l].size(); i++) {
      int q_1 = Ic1_index[l][i].q_1;
      int q_2 = Ic1_index[l][i].q_2;
      int q_3 = Ic1_index[l][i].q_3;
      int q_4 = Ic1_index[l][i].q_4;
      int lamb_2 = Ic1_index[l][i].lamb_2;
      int lamb_12 = Ic1_index[l][i].lamb_12;
      int lamb_1 = Ic1_index[l][i].lamb_1;
      int size_t = t014_state2[l].size();

      int lbar_min1 = std::abs(q_1 - q_2);
      int lbar_max1 = q_1 + q_2;
      int lbar_min2 = std::abs(q_3 - q_4);
      int lbar_max2 = q_3 + q_4;

      int lbar_minA = std::max(lbar_min1, lbar_min2);
      int lbar_maxA = std::min(lbar_max1, lbar_max2);

      for (int t = 0; t < size_t; t++) {
        int t0 = t014_state2[l][t].t_0;
        int t1 = t014_state2[l][t].t_1;
        int t4 = t014_state2[l][t].t_4;

        int lbar_min3 = std::abs(lamb_2 - t0);
        int lbar_max3 = lamb_2 + t0;
        int lbar_min4 = std::abs(lamb_1 - t1);
        int lbar_max4 = lamb_1 + t1;
        int lbar_min5 = std::abs(lamb_12 - t4);
        int lbar_max5 = lamb_12 + t4;

        int lbar_minB = std::max(lbar_min3, lbar_min4);
        int lbar_minC = std::max(lbar_minB, lbar_min5);
        int lbar_maxB = std::min(lbar_max3, lbar_max4);
        int lbar_maxC = std::min(lbar_maxB, lbar_max5);

        int lbar_min = std::max(lbar_minA, lbar_minC);
        int lbar_max = std::min(lbar_maxA, lbar_maxC);

        for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
          for (int i_1 = 0; i_1 <= lbar; i_1++) {
            int i_2 = lbar - i_1;
            int lbar12_minA = std::abs(i_1 - q_1);
            int lbar12_maxA = i_1 + q_1;
            int lbar12_minB = std::abs(i_2 - q_2);
            int lbar12_maxB = i_2 + q_2;
            int lbar12_min = std::max(lbar12_minA, lbar12_minB);
            int lbar12_max = std::min(lbar12_maxA, lbar12_maxB);
            for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
              for (int i_3 = 0; i_3 <= lbar; i_3++) {
                int i_4 = lbar - i_3;
                int lbar3_minA = std::abs(i_3 - q_3);
                int lbar3_maxA = i_3 + q_3;
                int lbar3_minB = std::abs(i_4 - q_4);
                int lbar3_maxB = i_4 + q_4;
                int lbar3_min = std::max(lbar3_minA, lbar3_minB);
                int lbar3_max = std::min(lbar3_maxA, lbar3_maxB);
                for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
                  int lbar_index = lb_vec[lbar][lbar12][lbar3];
                  Ic1_lbar_index_flag[l][lbar_index] = 1;
                  lbar_flag[lbar_index] = 1;
                }
              }
            }
          }
        }
      }
    }
    // cout << " --- Good 2-1 ? --- " << endl;
#pragma omp parallel for schedule(dynamic, 1)
    for (int i = 0; i < Ic3_index[l].size(); i++) {
      int q_1 = Ic3_index[l][i].q_1;
      int q_2 = Ic3_index[l][i].q_2;
      int q_3 = Ic3_index[l][i].q_3;
      int q_4 = Ic3_index[l][i].q_4;
      int s_3 = Ic3_index[l][i].s_3;
      int s_4 = Ic3_index[l][i].s_4;
      int lamb_1 = Ic3_index[l][i].lamb_1;
      int size_t = t014_state2[l].size();

      int lbar_min1 = std::abs(q_1 - q_2);
      int lbar_max1 = q_1 + q_2;
      int lbar_min2 = std::abs(q_3 - q_4);
      int lbar_max2 = q_3 + q_4;

      int lbar_minA = std::max(lbar_min1, lbar_min2);
      int lbar_maxA = std::min(lbar_max1, lbar_max2);

      for (int t = 0; t < size_t; t++) {
        int t0 = t014_state2[l][t].t_0;
        int t1 = t014_state2[l][t].t_1;
        int t4 = t014_state2[l][t].t_4;

        int lbar_min3 = std::abs(s_3 - t0);
        int lbar_max3 = s_3 + t0;
        int lbar_min4 = std::abs(lamb_1 - t1);
        int lbar_max4 = lamb_1 + t1;
        int lbar_min5 = std::abs(s_4 - t4);
        int lbar_max5 = s_4 + t4;

        int lbar_minB = std::max(lbar_min3, lbar_min4);
        int lbar_minC = std::max(lbar_minB, lbar_min5);
        int lbar_maxB = std::min(lbar_max3, lbar_max4);
        int lbar_maxC = std::min(lbar_maxB, lbar_max5);

        int lbar_min = std::max(lbar_minA, lbar_minC);
        int lbar_max = std::min(lbar_maxA, lbar_maxC);

        for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
          for (int i_1 = 0; i_1 <= lbar; i_1++) {
            int i_2 = lbar - i_1;
            int lbar12_minA = std::abs(i_1 - q_1);
            int lbar12_maxA = i_1 + q_1;
            int lbar12_minB = std::abs(i_2 - q_2);
            int lbar12_maxB = i_2 + q_2;
            int lbar12_min = std::max(lbar12_minA, lbar12_minB);
            int lbar12_max = std::min(lbar12_maxA, lbar12_maxB);
            for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
              for (int i_3 = 0; i_3 <= lbar; i_3++) {
                int i_4 = lbar - i_3;
                int lbar3_minA = std::abs(i_3 - q_3);
                int lbar3_maxA = i_3 + q_3;
                int lbar3_minB = std::abs(i_4 - q_4);
                int lbar3_maxB = i_4 + q_4;
                int lbar3_min = std::max(lbar3_minA, lbar3_minB);
                int lbar3_max = std::min(lbar3_maxA, lbar3_maxB);
                for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
                  int lbar_index = lb_vec[lbar][lbar12][lbar3];
                  Ic3_lbar_index_flag[l][lbar_index] = 1;
                  lbar_flag[lbar_index] = 1;
                }
              }
            }
          }
        }
      }
    }
  }

  //
  vector<vector<vector<int>>> Ic4_lbar_index_flag(3);
  cout << "Start to build Ic4" << endl;

  for (int s_0 = 0; s_0 <= 2; s_0++) {
    Ic4_lbar_index_flag[s_0].resize(size_l);
    for (int l = 0; l < Ic4_index[s_0].size(); l++) {
      Ic4_lbar_index_flag[s_0][l].resize(size_lbar);

      for (int i = 0; i < size_lbar; i++) {
        Ic4_lbar_index_flag[s_0][l][i] = -1;
      }
#pragma omp parallel for schedule(dynamic, 1)
      for (int i = 0; i < Ic4_index[s_0][l].size(); i++) {
        int q_1 = Ic4_index[s_0][l][i].q_1;
        int q_2 = Ic4_index[s_0][l][i].q_2;
        int q_3 = Ic4_index[s_0][l][i].q_3;
        int q_4 = Ic4_index[s_0][l][i].q_4;
        int s_3 = Ic4_index[s_0][l][i].s_3;
        int s_4 = Ic4_index[s_0][l][i].s_4;
        int lamb_1 = Ic4_index[s_0][l][i].lamb_1;
        int size_t = t014_state2[l].size();

        int lbar_min1 = std::abs(q_1 - q_2);
        int lbar_max1 = q_1 + q_2;
        int lbar_min2 = std::abs(q_3 - q_4);
        int lbar_max2 = q_3 + q_4;

        int lbar_minA = std::max(lbar_min1, lbar_min2);
        int lbar_maxA = std::min(lbar_max1, lbar_max2);

        for (int t = 0; t < size_t; t++) {
          int t0 = t014_state2[l][t].t_0;
          int t1 = t014_state2[l][t].t_1;
          int t4 = t014_state2[l][t].t_4;

          int lbar_min3 = std::abs(s_3 - t0);
          int lbar_max3 = s_3 + t0;
          int lbar_min4 = std::abs(lamb_1 - t1);
          int lbar_max4 = lamb_1 + t1;
          int lbar_min5 = std::abs(s_4 - t4);
          int lbar_max5 = s_4 + t4;

          int lbar_minB = std::max(lbar_min3, lbar_min4);
          int lbar_minC = std::max(lbar_minB, lbar_min5);
          int lbar_maxB = std::min(lbar_max3, lbar_max4);
          int lbar_maxC = std::min(lbar_maxB, lbar_max5);

          int lbar_min = std::max(lbar_minA, lbar_minC);
          int lbar_max = std::min(lbar_maxA, lbar_maxC);

          for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
            for (int i_1 = 0; i_1 <= lbar; i_1++) {
              int i_2 = lbar - i_1;
              int lbar12_minA = std::abs(i_1 - q_1);
              int lbar12_maxA = i_1 + q_1;
              int lbar12_minB = std::abs(i_2 - q_2);
              int lbar12_maxB = i_2 + q_2;
              int lbar12_min = std::max(lbar12_minA, lbar12_minB);
              int lbar12_max = std::min(lbar12_maxA, lbar12_maxB);
              for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
                for (int i_3 = 0; i_3 <= lbar; i_3++) {
                  int i_4 = lbar - i_3;
                  int lbar3_minA = std::abs(i_3 - q_3);
                  int lbar3_maxA = i_3 + q_3;
                  int lbar3_minB = std::abs(i_4 - q_4);
                  int lbar3_maxB = i_4 + q_4;
                  int lbar3_min = std::max(lbar3_minA, lbar3_minB);
                  int lbar3_max = std::min(lbar3_maxA, lbar3_maxB);
                  for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
                    int lbar_index = lb_vec[lbar][lbar12][lbar3];
                    Ic4_lbar_index_flag[s_0][l][lbar_index] = 1;
                    lbar_flag[lbar_index] = 1;
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  vector<lbar_struct_tpe> lbar_state_t;
  vector<vector<vector<int>>> lbar_vec_t;
  vector<int> lbar_index_Reduce2orig(lb_s.size(), -1);
  lbar_state_t = lb_s;
  lbar_vec_t = lb_vec;
  lb_s.clear();
  for (int lb = 0; lb < lb_vec.size(); lb++) {
    for (int lb12 = 0; lb12 < lb_vec[lb].size(); lb12++) {
      for (int lb3 = 0; lb3 < lb_vec[lb][lb12].size(); lb3++) {
        lb_vec[lb][lb12][lb3] = -1;
      }
    }
  }
  index = 0;
  for (int lb = 0; lb < lbar_state_t.size(); lb++) {
    if (lbar_flag[lb] > 0) {
      int lbar = lbar_state_t[lb].lbar;
      int lbar12 = lbar_state_t[lb].lbar12;
      int lbar3 = lbar_state_t[lb].lbar3;
      lb_s.push_back(lbar_state_t[lb]);
      lb_vec[lbar][lbar12][lbar3] = index;
      //
      lbar_index_Reduce2orig[index] = lbar_vec_t[lbar][lbar12][lbar3];
      //
      index++;
    }
  }
  lbar_state_t.clear();
  lbar_vec_t.clear();

  Llbar_Ic_R.resize(size_l);
  Llbar_Ic_R_vec.resize(size_l);
  for (int l = 0; l < size_l; l++) {
    Llbar_Ic_R_vec[l].resize(size_lbar);
    for (int lb_i = 0; lb_i < size_lbar; lb_i++)
      Llbar_Ic_R_vec[l][lb_i] = -1;
    int index_L = 0;
    for (int lb_i = 0; lb_i < size_lbar; lb_i++) {
      int flag = -1;
      int lb_i_ori = lbar_index_Reduce2orig[lb_i];
      if (Ic1_lbar_index_flag[l][lb_i_ori] > 0)
        flag = 1;
      if (Ic3_lbar_index_flag[l][lb_i_ori] > 0)
        flag = 1;
      if (flag < 0) {
        for (int s_0 = 0; s_0 <= 2; s_0++) {
          if (Ic4_lbar_index_flag[s_0][l][lb_i_ori] > 0)
            flag = 1;
        }
      }
      if (flag < 0)
        continue;
      Llbar_Ic_R[l].push_back(lb_i);
      Llbar_Ic_R_vec[l][lb_i] = index_L;
      index_L++;
    }
  }

  // cout << " Ic4 lbar max = " << lbar123_max
  //     << "\t Ic4 index all size = " << index << endl;
}

void Tpe_term::get_Llbar_info_loc(vector<l_struct> &l_state_loc,
                                  vector<int> &l_loc2unv,
                                  vector<lbar_struct_tpe> &lbar_state_loc,
                                  vector<vector<vector<int>>> &lbar_vec_loc,
                                  vector<vector<int>> &Llbar_Ic_Reduced_loc,
                                  vector<vector<int>> &Llbar_Ic_Red_vec_loc) {
  int size_l = l_state.size();
  int size_l_loc = l_state_loc.size();
  if (size_l > size_l) {
    cout << "Wrong happened at Tpe_term::get_Llbar_info : size_l > size_l_unv"
         << endl;
    exit(0);
  }
  // map from l_state_loc -> l_state
  // std::vector<int> l_loc2unv(size_l);
  l_loc2unv.resize(size_l_loc);
  for (int i = 0; i < size_l_loc; i++) {
    int l12p = l_state_loc[i].l12p;
    int l3p = l_state_loc[i].l3p;
    int l12 = l_state_loc[i].l12;
    int l3 = l_state_loc[i].l3;
    int flag = -1;
    for (int j = 0; j < size_l; j++) {
      int l12p_x = l_state[i].l12p;
      int l3p_x = l_state[i].l3p;
      int l12_x = l_state[i].l12;
      int l3_x = l_state[i].l3;
      if (l12p != l12p_x)
        continue;
      if (l3p != l3p_x)
        continue;
      if (l12 != l12_x)
        continue;
      if (l3 != l3_x)
        continue;
      l_loc2unv[i] = j;
      flag = 1;
      break;
    }
    if (flag < 0) {
      cout << "Wrong happened at Tpe_term::get_Llbar_info : map from "
              "l_state_loc -> l_state"
           << endl;
      exit(0);
    }
  }
  // construct lbar_state_loc
  int lbar_max_t = 0;
  for (int s_0 = 0; s_0 <= 2; s_0++) {
    for (int l_loc = 0; l_loc < size_l_loc; l_loc++) {
      int l = l_loc2unv[l_loc];
      for (int i = 0; i < Ic4_index[s_0][l].size(); i++) {
        int q_1 = Ic4_index[s_0][l][i].q_1;
        int q_2 = Ic4_index[s_0][l][i].q_2;
        int q_3 = Ic4_index[s_0][l][i].q_3;
        int q_4 = Ic4_index[s_0][l][i].q_4;
        int s_3 = Ic4_index[s_0][l][i].s_3;
        int s_4 = Ic4_index[s_0][l][i].s_4;
        int lamb_1 = Ic4_index[s_0][l][i].lamb_1;
        int size_t = t014_state2[l].size();

        int lbar_min1 = std::abs(q_1 - q_2);
        int lbar_max1 = q_1 + q_2;
        int lbar_min2 = std::abs(q_3 - q_4);
        int lbar_max2 = q_3 + q_4;

        int lbar_minA = std::max(lbar_min1, lbar_min2);
        int lbar_maxA = std::min(lbar_max1, lbar_max2);

        for (int t = 0; t < size_t; t++) {
          int t0 = t014_state2[l][t].t_0;
          int t1 = t014_state2[l][t].t_1;
          int t4 = t014_state2[l][t].t_4;

          int lbar_min3 = std::abs(s_3 - t0);
          int lbar_max3 = s_3 + t0;
          int lbar_min4 = std::abs(lamb_1 - t1);
          int lbar_max4 = lamb_1 + t1;
          int lbar_min5 = std::abs(s_4 - t4);
          int lbar_max5 = s_4 + t4;

          int lbar_minB = std::max(lbar_min3, lbar_min4);
          int lbar_minC = std::max(lbar_minB, lbar_min5);
          int lbar_maxB = std::min(lbar_max3, lbar_max4);
          int lbar_maxC = std::min(lbar_maxB, lbar_max5);

          int lbar_min = std::max(lbar_minA, lbar_minC);
          int lbar_max = std::min(lbar_maxA, lbar_maxC);

          if (lbar_max > lbar_max_t)
            lbar_max_t = lbar_max;
        }
      }
    }
  }
  // this->lbar123_max = lbar_max_t;
  // this->Ic4_lbar_max = lbar_max_t;
  // if (TpeCom.rank() == 0)
  //  cout << " Ic4 lbar max = " << lbar123_max << endl;

  // cout << "Start to Build lbar_stat in TPE" << endl;
  int lbar12_max = lbar123_max;
  int lbar3_max = lbar123_max;
  int index = 0;
  lbar_struct_tpe lbar_state_t;
  lbar_state_loc.clear();
  lbar_vec_loc.resize(lbar123_max + 1);
  for (int l1 = 0; l1 <= lbar123_max; l1++) {
    lbar_vec_loc[l1].resize(lbar12_max + 1);
    for (int l2 = 0; l2 <= lbar12_max; l2++) {
      lbar_vec_loc[l1][l2].resize(lbar3_max + 1);
      for (int l3 = 0; l3 <= lbar3_max; l3++) {
        lbar_vec_loc[l1][l2][l3] = index;
        lbar_state_t.lbar = l1;
        lbar_state_t.lbar12 = l2;
        lbar_state_t.lbar3 = l3;
        lbar_state_loc.push_back(lbar_state_t);
        index++;
      }
    }
  }

  // Start to Build Llbar_Ic_Reduced in TPE
  // cout << "Start to Build Llbar_Ic_Reduced in TPE" << endl;
  int size_lbar = lbar_state_loc.size();
  vector<vector<int>> Ic1_lbar_index_flag(size_l_loc);
  vector<vector<int>> Ic3_lbar_index_flag(size_l_loc);

  for (int l_loc = 0; l_loc < size_l_loc; l_loc++) {
    Ic1_lbar_index_flag[l_loc].resize(size_lbar);
    Ic3_lbar_index_flag[l_loc].resize(size_lbar);

    for (int i = 0; i < size_lbar; i++) {
      Ic1_lbar_index_flag[l_loc][i] = -1;
      Ic3_lbar_index_flag[l_loc][i] = -1;
    }
    int l = l_loc2unv[l_loc];
#pragma omp parallel for schedule(dynamic, 1)
    for (int i = 0; i < Ic1_index[l].size(); i++) {
      int q_1 = Ic1_index[l][i].q_1;
      int q_2 = Ic1_index[l][i].q_2;
      int q_3 = Ic1_index[l][i].q_3;
      int q_4 = Ic1_index[l][i].q_4;
      int lamb_2 = Ic1_index[l][i].lamb_2;
      int lamb_12 = Ic1_index[l][i].lamb_12;
      int lamb_1 = Ic1_index[l][i].lamb_1;
      int size_t = t014_state2[l].size();

      int lbar_min1 = std::abs(q_1 - q_2);
      int lbar_max1 = q_1 + q_2;
      int lbar_min2 = std::abs(q_3 - q_4);
      int lbar_max2 = q_3 + q_4;

      int lbar_minA = std::max(lbar_min1, lbar_min2);
      int lbar_maxA = std::min(lbar_max1, lbar_max2);

      for (int t = 0; t < size_t; t++) {
        int t0 = t014_state2[l][t].t_0;
        int t1 = t014_state2[l][t].t_1;
        int t4 = t014_state2[l][t].t_4;

        int lbar_min3 = std::abs(lamb_2 - t0);
        int lbar_max3 = lamb_2 + t0;
        int lbar_min4 = std::abs(lamb_1 - t1);
        int lbar_max4 = lamb_1 + t1;
        int lbar_min5 = std::abs(lamb_12 - t4);
        int lbar_max5 = lamb_12 + t4;

        int lbar_minB = std::max(lbar_min3, lbar_min4);
        int lbar_minC = std::max(lbar_minB, lbar_min5);
        int lbar_maxB = std::min(lbar_max3, lbar_max4);
        int lbar_maxC = std::min(lbar_maxB, lbar_max5);

        int lbar_min = std::max(lbar_minA, lbar_minC);
        int lbar_max = std::min(lbar_maxA, lbar_maxC);

        for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
          for (int i_1 = 0; i_1 <= lbar; i_1++) {
            int i_2 = lbar - i_1;
            int lbar12_minA = std::abs(i_1 - q_1);
            int lbar12_maxA = i_1 + q_1;
            int lbar12_minB = std::abs(i_2 - q_2);
            int lbar12_maxB = i_2 + q_2;
            int lbar12_min = std::max(lbar12_minA, lbar12_minB);
            int lbar12_max = std::min(lbar12_maxA, lbar12_maxB);
            for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
              for (int i_3 = 0; i_3 <= lbar; i_3++) {
                int i_4 = lbar - i_3;
                int lbar3_minA = std::abs(i_3 - q_3);
                int lbar3_maxA = i_3 + q_3;
                int lbar3_minB = std::abs(i_4 - q_4);
                int lbar3_maxB = i_4 + q_4;
                int lbar3_min = std::max(lbar3_minA, lbar3_minB);
                int lbar3_max = std::min(lbar3_maxA, lbar3_maxB);
                for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
                  int lbar_index = lbar_vec_loc[lbar][lbar12][lbar3];
                  Ic1_lbar_index_flag[l_loc][lbar_index] = 1;
                }
              }
            }
          }
        }
      }
    }

#pragma omp parallel for schedule(dynamic, 1)
    for (int i = 0; i < Ic3_index[l].size(); i++) {
      int q_1 = Ic3_index[l][i].q_1;
      int q_2 = Ic3_index[l][i].q_2;
      int q_3 = Ic3_index[l][i].q_3;
      int q_4 = Ic3_index[l][i].q_4;
      int s_3 = Ic3_index[l][i].s_3;
      int s_4 = Ic3_index[l][i].s_4;
      int lamb_1 = Ic3_index[l][i].lamb_1;
      int size_t = t014_state2[l].size();

      int lbar_min1 = std::abs(q_1 - q_2);
      int lbar_max1 = q_1 + q_2;
      int lbar_min2 = std::abs(q_3 - q_4);
      int lbar_max2 = q_3 + q_4;

      int lbar_minA = std::max(lbar_min1, lbar_min2);
      int lbar_maxA = std::min(lbar_max1, lbar_max2);

      for (int t = 0; t < size_t; t++) {
        int t0 = t014_state2[l][t].t_0;
        int t1 = t014_state2[l][t].t_1;
        int t4 = t014_state2[l][t].t_4;

        int lbar_min3 = std::abs(s_3 - t0);
        int lbar_max3 = s_3 + t0;
        int lbar_min4 = std::abs(lamb_1 - t1);
        int lbar_max4 = lamb_1 + t1;
        int lbar_min5 = std::abs(s_4 - t4);
        int lbar_max5 = s_4 + t4;

        int lbar_minB = std::max(lbar_min3, lbar_min4);
        int lbar_minC = std::max(lbar_minB, lbar_min5);
        int lbar_maxB = std::min(lbar_max3, lbar_max4);
        int lbar_maxC = std::min(lbar_maxB, lbar_max5);

        int lbar_min = std::max(lbar_minA, lbar_minC);
        int lbar_max = std::min(lbar_maxA, lbar_maxC);

        for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
          for (int i_1 = 0; i_1 <= lbar; i_1++) {
            int i_2 = lbar - i_1;
            int lbar12_minA = std::abs(i_1 - q_1);
            int lbar12_maxA = i_1 + q_1;
            int lbar12_minB = std::abs(i_2 - q_2);
            int lbar12_maxB = i_2 + q_2;
            int lbar12_min = std::max(lbar12_minA, lbar12_minB);
            int lbar12_max = std::min(lbar12_maxA, lbar12_maxB);
            for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
              for (int i_3 = 0; i_3 <= lbar; i_3++) {
                int i_4 = lbar - i_3;
                int lbar3_minA = std::abs(i_3 - q_3);
                int lbar3_maxA = i_3 + q_3;
                int lbar3_minB = std::abs(i_4 - q_4);
                int lbar3_maxB = i_4 + q_4;
                int lbar3_min = std::max(lbar3_minA, lbar3_minB);
                int lbar3_max = std::min(lbar3_maxA, lbar3_maxB);
                for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
                  int lbar_index = lbar_vec_loc[lbar][lbar12][lbar3];
                  Ic3_lbar_index_flag[l_loc][lbar_index] = 1;
                }
              }
            }
          }
        }
      }
    }
  }

  //
  vector<vector<vector<int>>> Ic4_lbar_index_flag(3);
  cout << "Start to build Ic4" << endl;

  for (int s_0 = 0; s_0 <= 2; s_0++) {
    Ic4_lbar_index_flag[s_0].resize(size_l_loc);
    for (int l_loc = 0; l_loc < size_l_loc; l_loc++) {
      // for (int l = 0; l < Ic4_index[s_0].size(); l++) {
      int l = l_loc2unv[l_loc];
      Ic4_lbar_index_flag[s_0][l_loc].resize(size_lbar);

      for (int i = 0; i < size_lbar; i++) {
        Ic4_lbar_index_flag[s_0][l_loc][i] = -1;
      }
#pragma omp parallel for schedule(dynamic, 1)
      for (int i = 0; i < Ic4_index[s_0][l].size(); i++) {
        int q_1 = Ic4_index[s_0][l][i].q_1;
        int q_2 = Ic4_index[s_0][l][i].q_2;
        int q_3 = Ic4_index[s_0][l][i].q_3;
        int q_4 = Ic4_index[s_0][l][i].q_4;
        int s_3 = Ic4_index[s_0][l][i].s_3;
        int s_4 = Ic4_index[s_0][l][i].s_4;
        int lamb_1 = Ic4_index[s_0][l][i].lamb_1;
        int size_t = t014_state2[l].size();

        int lbar_min1 = std::abs(q_1 - q_2);
        int lbar_max1 = q_1 + q_2;
        int lbar_min2 = std::abs(q_3 - q_4);
        int lbar_max2 = q_3 + q_4;

        int lbar_minA = std::max(lbar_min1, lbar_min2);
        int lbar_maxA = std::min(lbar_max1, lbar_max2);

        for (int t = 0; t < size_t; t++) {
          int t0 = t014_state2[l][t].t_0;
          int t1 = t014_state2[l][t].t_1;
          int t4 = t014_state2[l][t].t_4;

          int lbar_min3 = std::abs(s_3 - t0);
          int lbar_max3 = s_3 + t0;
          int lbar_min4 = std::abs(lamb_1 - t1);
          int lbar_max4 = lamb_1 + t1;
          int lbar_min5 = std::abs(s_4 - t4);
          int lbar_max5 = s_4 + t4;

          int lbar_minB = std::max(lbar_min3, lbar_min4);
          int lbar_minC = std::max(lbar_minB, lbar_min5);
          int lbar_maxB = std::min(lbar_max3, lbar_max4);
          int lbar_maxC = std::min(lbar_maxB, lbar_max5);

          int lbar_min = std::max(lbar_minA, lbar_minC);
          int lbar_max = std::min(lbar_maxA, lbar_maxC);

          for (int lbar = lbar_min; lbar <= lbar_max; lbar++) {
            for (int i_1 = 0; i_1 <= lbar; i_1++) {
              int i_2 = lbar - i_1;
              int lbar12_minA = std::abs(i_1 - q_1);
              int lbar12_maxA = i_1 + q_1;
              int lbar12_minB = std::abs(i_2 - q_2);
              int lbar12_maxB = i_2 + q_2;
              int lbar12_min = std::max(lbar12_minA, lbar12_minB);
              int lbar12_max = std::min(lbar12_maxA, lbar12_maxB);
              for (int lbar12 = lbar12_min; lbar12 <= lbar12_max; lbar12++) {
                for (int i_3 = 0; i_3 <= lbar; i_3++) {
                  int i_4 = lbar - i_3;
                  int lbar3_minA = std::abs(i_3 - q_3);
                  int lbar3_maxA = i_3 + q_3;
                  int lbar3_minB = std::abs(i_4 - q_4);
                  int lbar3_maxB = i_4 + q_4;
                  int lbar3_min = std::max(lbar3_minA, lbar3_minB);
                  int lbar3_max = std::min(lbar3_maxA, lbar3_maxB);
                  for (int lbar3 = lbar3_min; lbar3 <= lbar3_max; lbar3++) {
                    int lbar_index = lbar_vec_loc[lbar][lbar12][lbar3];
                    Ic4_lbar_index_flag[s_0][l_loc][lbar_index] = 1;
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  //
  Llbar_Ic_Reduced_loc.resize(size_l_loc);
  Llbar_Ic_Red_vec_loc.resize(size_l_loc);
  for (int l_loc = 0; l_loc < size_l_loc; l_loc++) {
    Llbar_Ic_Red_vec_loc[l_loc].resize(size_lbar);
    for (int lb_i = 0; lb_i < size_lbar; lb_i++)
      Llbar_Ic_Red_vec_loc[l_loc][lb_i] = -1;
    int index = 0;
    for (int lb_i = 0; lb_i < size_lbar; lb_i++) {
      int flag = -1;

      if (Ic1_lbar_index_flag[l_loc][lb_i] > 0)
        flag = 1;
      if (Ic3_lbar_index_flag[l_loc][lb_i] > 0)
        flag = 1;
      if (flag < 0) {
        for (int s_0 = 0; s_0 <= 2; s_0++) {
          if (Ic4_lbar_index_flag[s_0][l_loc][lb_i] > 0)
            flag = 1;
        }
      }
      if (flag < 0)
        continue;
      Llbar_Ic_Reduced_loc[l_loc].push_back(lb_i);
      Llbar_Ic_Red_vec_loc[l_loc][lb_i] = index;
      index++;
    }
  }

  // cout << " Ic4 lbar max = " << lbar123_max
  //     << "\t Ic4 index all size = " << index << endl;
}

void Tpe_term::Jlpl_build(int Emax_F, int Emax_I, vector<vector<int>> E_JC,
                          vector<l_struct> &l_state_x,
                          vector<vector<vector<vector<int>>>> &l_vec_x,
                          vector<vector<vector<Jaco_lpl_struct>>> &Jlpl_x,
                          vector<int> &mpi_task_Init,
                          vector<vector<int>> &dis_task) {

  // calculate Jlpl, the configuration of Jacobi initial and final state
  int lpl_size = l_state_x.size();
  Jlpl_x.resize(lpl_size);
  int channel_size = jaco.state.size();
  cout << "lpl_size = " << lpl_size << "\t ch_size = " << channel_size
       << "\t on : " << TpeEnv.processor_name() << endl;
  for (int l = 0; l < lpl_size; l++) {

    int l12p = l_state_x[l].l12p;
    int l3p = l_state_x[l].l3p;
    int l12 = l_state_x[l].l12;
    int l3 = l_state_x[l].l3;

    Jlpl_x[l].resize(channel_size);
    for (int ch = 0; ch < channel_size; ch++) {
      int index_jaco = 0;
      for (int f = 0; f < jaco.state[ch].size(); f++) {
        if (jaco.state[ch][f].F < 0)
          continue;
        int l12_f = jaco.state[ch][f].l12;
        int l3_f = jaco.state[ch][f].l3;
        if (l12_f != l12p)
          continue;
        if (l3_f != l3p)
          continue;
        int Par_p = this->phase(l12_f + l3_f);

        int E_p =
            2 * (jaco.state[ch][f].n12 + jaco.state[ch][f].n3) + l12_f + l3_f;
        vector<int> E_p_pos;
        for (int k1 = 0; k1 < E_JC.size(); k1++) {
          if (E_p == E_JC[k1][0]) {
            E_p_pos.push_back(k1);
          }
        }
        if (E_p_pos.size() == 0)
          continue;

        for (int i = 0; i < jaco.state[ch].size(); i++) {
          if (jaco.state[ch][i].I < 0)
            continue;
          int l12_i = jaco.state[ch][i].l12;
          int l3_i = jaco.state[ch][i].l3;
          if (l12_i != l12)
            continue;
          if (l3_i != l3)
            continue;
          int Par = this->phase(l12_i + l3_i);
          if (Par_p != Par)
            continue;

          int E = 2 * (jaco.state[ch][i].n12 + jaco.state[ch][i].n3) +
                  jaco.state[ch][i].l12 + jaco.state[ch][i].l3;
          int E_JC_flag = -1;
          for (int k2 = 0; k2 < E_p_pos.size(); k2++) {
            int a = E_p_pos[k2];
            if (E == E_JC[a][1]) {
              E_JC_flag = 1;
              break;
            }
          }
          if (E_p <= Emax_F && E <= Emax_I && E_JC_flag == 1) {
            Jaco_lpl_struct Jlpl_t;
            Jlpl_t.i = i;
            Jlpl_t.f = f;
            Jlpl_x[l][ch].push_back(Jlpl_t);
          }
        }
      }
    }
  }
  // cout << "Good 1 on : " << TpeEnv.processor_name() << endl;
  if (TpeCom.rank() == 0) {
    std::ofstream file_lpl;
    file_lpl.open("data/l_state_x_tpe.dat");
    file_lpl << "i\t l12p\t l3p\t l12\t l3\t " << endl;
    for (int i = 0; i < l_state_x.size(); i++) {
      file_lpl << i << "\t" << l_state_x[i].l12p;
      file_lpl << "\t" << l_state_x[i].l3p;
      file_lpl << "\t" << l_state_x[i].l12;
      file_lpl << "\t" << l_state_x[i].l3 << endl;
    }
    file_lpl.close();

    std::ofstream file_Jlpl;
    file_Jlpl.open("data/Jlpl.dat");
    for (int ch = 0; ch < channel_size; ch++) {
      file_Jlpl << " == channel : " << ch << " == " << endl;
      for (int l = 0; l < lpl_size; l++) {
        file_Jlpl << " \t lpl index : " << l << endl;
        file_Jlpl << "No.\t final_index\t init_index" << endl;
        for (int i = 0; i < Jlpl_x[l][ch].size(); i++) {
          file_Jlpl << i << "\t" << Jlpl_x[l][ch][i].f << "\t"
                    << Jlpl_x[l][ch][i].i << endl;
        }
      }
    }
    file_Jlpl.close();
  }
  // cout << "Good 2 on : " << TpeEnv.processor_name() << endl;
  // Finde & Delete init_index <-> finial_index in same channel
  for (int ch = 0; ch < channel_size; ch++) {
    for (int a = 0; a < lpl_size; a++) {
      if (Jlpl_x[a][ch].size() == 0)
        continue;

      for (int ia = 0; ia < Jlpl_x[a][ch].size(); ia++) {
        int A_init = Jlpl_x[a][ch][ia].i;
        int A_final = Jlpl_x[a][ch][ia].f;

        int l12p_a = l_state_x[a].l12p;
        int l3p_a = l_state_x[a].l3p;
        int l12_a = l_state_x[a].l12;
        int l3_a = l_state_x[a].l3;
        for (int b = a; b < lpl_size; b++) {
          if (Jlpl_x[b][ch].size() == 0)
            continue;
          int l12p_b = l_state_x[b].l12p;
          int l3p_b = l_state_x[b].l3p;
          int l12_b = l_state_x[b].l12;
          int l3_b = l_state_x[b].l3;
          if (l12p_b != l12_a || l3p_b != l3_a)
            continue;
          if (l12_b != l12p_a || l3_b != l3p_a)
            continue;
          auto it = Jlpl_x[b][ch].begin();
          while (it != Jlpl_x[b][ch].end()) {
            int B_init = it->i;
            int B_final = it->f;
            if (A_init == B_final && A_final == B_init && B_init != B_final) {
              it = Jlpl_x[b][ch].erase(it);
            } else {
              it++;
            }
          }
        }
      }
    }
  }
  // cout << "Good 3 on : " << TpeEnv.processor_name() << endl;
  // Update l_state & l_vec-- Jlpl_x ---------------------//
  for (int l1 = 0; l1 < l_vec.size(); l1++) {
    for (int l2 = 0; l2 < l_vec[l1].size(); l2++) {
      for (int l3 = 0; l3 < l_vec[l1][l2].size(); l3++) {
        for (int l4 = 0; l4 < l_vec[l1][l2][l3].size(); l4++) {
          l_vec[l1][l2][l3][l4] = -1;
        }
      }
    }
  }
  vector<l_struct> l_state_t;
  vector<vector<vector<Jaco_lpl_struct>>> Jlpl_t;
  l_state_t = l_state_x;
  Jlpl_t = Jlpl_x;
  // for (int i = 0; i < l_state_x.size(); i++) {
  //   l_state_t.push_back(l_state_x[i]);
  // }
  // Jlpl_t.resize(Jlpl_x.size());
  // for (int l = 0; l < Jlpl_x.size(); l++) {
  //   int ch_size = Jlpl_x[l].size();
  //   Jlpl_t[l].resize(ch_size);
  //   for (int ch = 0; ch < ch_size; ch++) {
  //     int i_size = Jlpl_x[l][ch].size();
  //     for(int i=0; i<i_size; i++)
  //     Jlpl_t[l][ch].push_back(Jlpl_x[l][ch][i]);
  //   }
  // }
  l_state_x.clear();
  Jlpl_x.clear();
  int index = 0;
  // cout<<" -- l_state_x.size() = "<<l_state_x.size()<<"\t l_state_t.size() = "<<l_state_t.size()<<endl;
  // cout<<" -- Jlpl_x.size() = "<<Jlpl_x.size()<<"\t Jlpl_t.size() = "<<Jlpl_t.size()<<endl;
  for (int l=0; l < l_state_t.size(); l++) {
    int ch_size = Jlpl_t[l].size();
    int num = 0;
    for (int ch = 0; ch < ch_size; ch++) {
      num += Jlpl_t[l][ch].size();
    }
    //cout<<"\t\t ** l = "<<l<<"\t num = "<<num<<endl;
    if (num > 0) {
      l_state_x.push_back(l_state_t[l]);
      Jlpl_x.push_back(Jlpl_t[l]);
      int l12p = l_state_t[l].l12p;
      int l3p = l_state_t[l].l3p;
      int l12 = l_state_t[l].l12;
      int l3 = l_state_t[l].l3;
      l_vec[l12p][l12][l3p][l3] = index;
      index++;
    }
  }
  lpl_size = l_state_x.size();
  l_state_t.clear();
  Jlpl_t.clear();
  // cout<<" ++ l_state_x.size() = "<<l_state_x.size()<<"\t l_state_t.size() = "<<l_state_t.size()<<endl;
  // cout<<" ++ Jlpl_x.size() = "<<Jlpl_x.size()<<"\t Jlpl_t.size() = "<<Jlpl_t.size()<<endl;

  if (TpeCom.rank() == 0) {
    std::ofstream file_lpl_D;
    file_lpl_D.open("data/l_state_changed.dat");
    file_lpl_D << "i\t l12p\t l3p\t l12\t l3\t " << endl;
    for (int i = 0; i < l_state_x.size(); i++) {
      file_lpl_D << i << "\t" << l_state_x[i].l12p;
      file_lpl_D << "\t" << l_state_x[i].l3p;
      file_lpl_D << "\t" << l_state_x[i].l12;
      file_lpl_D << "\t" << l_state_x[i].l3 << endl;
    }
    file_lpl_D.close();
  }
  //--------------------------------------------//

  // exit(0);
  // vector<vector<int>> dis_task;
  // vector<int> mpi_task_Init;

  mpi_task_Init.resize(lpl_size);
  for (int l = 0; l < lpl_size; l++) {
    int num = 0;
    int ch_size_t = Jlpl_x[l].size();
    for (int ch = 0; ch < ch_size_t; ch++) {
      num += Jlpl_x[l][ch].size();
    }
    mpi_task_Init[l] = num;
  }
  Task_Distr(mpi_task_Init, TpeCom.size(), dis_task);

  // boost::mpi::broadcast(TpeCom, mpi_task_Init, 0);
  // boost::mpi::broadcast(TpeCom, dis_task, 0);

  if (TpeCom.rank() == 0) {
    std::ofstream file_Jlpl_D;
    file_Jlpl_D.open("data/Jlpl_delete.dat");
    file_Jlpl_D << "MPI task : proc(num)" << endl;
    int Nodes = dis_task.size();
    for (int i = 0; i < Nodes; i++) {
      int size = dis_task[i].size();
      int tot_num = 0;

      file_Jlpl_D << "Nodes No. : " << i << "\t ";
      for (int j = 0; j < size; j++) {
        int A = dis_task[i][j];
        int task_num = mpi_task_Init[A];
        tot_num += task_num;
        file_Jlpl_D << A << "(" << task_num << ") \t";
      }
      file_Jlpl_D << "Tot task : " << tot_num << endl;
    }
    file_Jlpl_D << "~~~~~~~~~~~~~~~~" << endl;
    for (int l = 0; l < lpl_size; l++) {
      file_Jlpl_D << " \t ======  lpl index : " << l << " ======" << endl;
      int ch_size_t = Jlpl_x[l].size();
      for (int ch = 0; ch < ch_size_t; ch++) {
        file_Jlpl_D << " -- channel : " << ch << " -- " << endl;
        file_Jlpl_D << "No.\t final_index\t init_index" << endl;
        for (int i = 0; i < Jlpl_x[l][ch].size(); i++) {
          file_Jlpl_D << i << "\t" << Jlpl_x[l][ch][i].f << "\t"
                      << Jlpl_x[l][ch][i].i << endl;
        }
      }
    }
    file_Jlpl_D.close();
  }
}

void Tpe_term::build_nlpnl() {
  int ch_size = jaco.channel.size();
  this->vec.resize(ch_size);
  this->vec1.resize(ch_size);
  this->vec3.resize(ch_size);
  this->vec4.resize(ch_size);
  // Pgs_Bar pgs(ch_size, 30);
  // pgs.init()
  cout << "Begin to build Tpe term nlpnl :" << endl;
  for (int i = 0; i < ch_size; i++) {
    // pgs.PrintBar(i);
    int size = jaco.state[i].size();
    vec[i].resize(size);
    vec1[i].resize(size);
    vec3[i].resize(size);
    vec4[i].resize(size);
    // if(size<1)continue;
    // std::cout << "channel : " << i << endl;
    for (int x = 0; x < size; x++) {
      vec[i][x].resize(size);
      vec1[i][x].resize(size);
      vec3[i][x].resize(size);
      vec4[i][x].resize(size);
      for (int y = 0; y < size; y++) {
        vec[i][x][y] = 0.0;
        vec1[i][x][y] = 0.0;
        vec3[i][x][y] = 0.0;
        vec4[i][x][y] = 0.0;
      }
    }
  }
  for (int n = 0; n < nlpnl_size; n++) {
    for (int ch = 0; ch < ch_size; ch++) {
      for (int i = 0; i < Jnlp[n][ch].size(); i++) {
        int x = Jnlp[n][ch][i].f;
        int y = Jnlp[n][ch][i].i;
        double val1 = this->C1_term2(jaco.state[ch][x], jaco.state[ch][y]);
        // cout << "C1_term : " << val1 << "\t C1_term2 : " << val11 << endl;
        // double val3 = this->C3_term(jaco.state[i][x], jaco.state[i][y]);
        double val3 = this->C3_term2(jaco.state[ch][x], jaco.state[ch][y]);
        // cout << "C3_term : " << val3 << "\t C3_term2 : " << val33 << endl;
        // double val4 = this->C4_term(jaco.state[i][x], jaco.state[i][y]);
        double val4 = this->C4_term2(jaco.state[ch][x], jaco.state[ch][y]);
        // cout << "C4_term : " << val4 << "\t C4_term2 : " << val44 << endl;
        vec[ch][x][y] = val1 + val3 + val4;
        vec[ch][y][x] = val1 + val3 + val4;
        vec1[ch][x][y] = val1;
        vec1[ch][y][x] = val1;
        vec3[ch][x][y] = val3;
        vec3[ch][y][x] = val3;
        vec4[ch][x][y] = val4;
        vec4[ch][y][x] = val4;
      }
    }
  }
}

void Tpe_term::TPE_Build_MPI(vector<vector<int>> E_Jac_conf) {
  // ----- calculate lbar_state & lbar_vec  --- //
  //  for glbarS
  int lbar_max;
  vector<lbar_struct_tpe> lb_s;
  vector<vector<vector<int>>> lb_vec;
  vector<vector<int>> Llbar_Ic_R;
  vector<vector<int>> Llbar_Ic_R_vec;
  if (TpeCom.rank() == 0) {
    this->get_Llbar_info(lb_s, lb_vec, lbar_max, Llbar_Ic_R, Llbar_Ic_R_vec);
    cout << "TPE lbar123_max = " << lbar_max << endl;
  }
  // exit(0);
  boost::mpi::broadcast(TpeCom, lbar_max, 0);
  boost::mpi::broadcast(TpeCom, lb_s, 0);
  boost::mpi::broadcast(TpeCom, lb_vec, 0);
  boost::mpi::broadcast(TpeCom, Llbar_Ic_R, 0);
  boost::mpi::broadcast(TpeCom, Llbar_Ic_R_vec, 0);
  this->lbar_state = lb_s;
  this->lbar_vec = lb_vec;
  this->lbar123_max = lbar_max;
  this->Ic4_lbar_max = lbar_max;
  this->Llbar_Ic_Reduced = Llbar_Ic_R;
  this->Llbar_Ic_Red_vec = Llbar_Ic_R_vec;
  lb_s.clear();
  lb_vec.clear();
  Llbar_Ic_R.clear();
  Llbar_Ic_R_vec.clear();

  // ------------------ End --------------------- //
  // exit(0);
  // ------  ------------------ Wave glbarS Start ------------------ ------ //
  //  MPI by s-lbar
  int n_max = jaco.nmax;
  int l_max = jaco.lmax;
  int lbarS = lbar_max;
  int EJC_max = jaco.Emax;
  if (TpeCom.rank() == 0) {
    cout << " n_max = " << n_max << "\t l_max = " << l_max
         << "\t lbarS = " << lbarS << "\t EJC_max = " << EJC_max << endl;
  }
  wave.init(n_max, l_max, lbarS, EJC_max, TpeCom.rank());
  Time_Count TC_2;
  TC_2.start();
  int lmax_legendrePlW = lbarS;
  int lbarS_G = lbarS;
  int lbarS_gg = lbarS_G;

  wave.glbarS_init(lbarS_gg, lbarS_gg, lbarS_gg, lmax_legendrePlW);
  if (TpeCom.rank() == 0) {
    cout << "\t lbar_glbarS_max = " << wave.lbar_glbarS_max
         << "\t lbar_state_g.size() = " << wave.lbar_state_g.size() << endl;
  }
  // int size_u = wave.legendreP_x.size();
  // int kpk_12 = wave.kpk_vec[0][0];
  // int kpk_3 = wave.kpk_vec[0][0];
  // if (TpeCom.rank() == 0)
  //  wave.glbarS_cal_for_check(2, 2, 10, 10, 10, size_u, kpk_12, kpk_3);

  // exit(0);
  int mpi_run_flag = 1;
  cout << "\t  -- test Point A --" << endl;
  vector<int> mpi_run_flag_gather(TpeCom.size());
  all_gather(TpeCom, mpi_run_flag, mpi_run_flag_gather);
  // exit(0);
  /*Becareful glbarS_vec_build_MPI_II() could be wrong */
  // wave.glbarS_vec_build_MPI_II();
  //wave.glbarS_vec_build();
  wave.glbarS_vec_build_quick();
  TpeCom.barrier();

  cout << "glbarS_vec_build_MPI initial&calculate Time cost : " << TC_2.sec()
       << "s\t on Node : " << TpeEnv.processor_name() << endl;

  // exit(0);
  // ------ ------------------------------------------------------ ------ //

  // -------------------- Distribut Tasks by l_state -------------------- //
  // Jlpl_mpi_task_all; //[l_state] = number of Jacobi state combinations
  // Jlpl_mpi_task_dis; //[No. of nodes][0-x] = l_state
  // They were calculated in Jlpl_build in init_II
  int print_flag = -1;

  if (TpeCom.rank() == 0) {
    cout << "MPI task : proc(num)" << endl;
    int Nodes = this->Jlpl_mpi_task_dis.size();
    for (int i = 0; i < Nodes; i++) {
      int size = this->Jlpl_mpi_task_dis[i].size();
      int tot_num = 0;
      if (print_flag > 0)
        cout << "Nodes No. : " << i << "\t ";
      for (int j = 0; j < size; j++) {
        int A = this->Jlpl_mpi_task_dis[i][j];
        int task_num = this->Jlpl_mpi_task_all[A];
        tot_num += task_num;
        if (print_flag > 0)
          cout << A << "(" << task_num << ") \t";
      }
      if (print_flag > 0)
        cout << "Tot task : " << tot_num << endl;
    }
  }
  all_gather(TpeCom, mpi_run_flag, mpi_run_flag_gather);
  int my_rank = TpeCom.rank();
  vector<l_struct_wave> l_state_node;
  vector<vector<vector<vector<int>>>> l_vec_node; //[l12p][l12][l3p][l3]
  vector<vector<int>> Llbar_Ic_R_node;
  vector<vector<int>> Llbar_Ic_R_vec_node;
  l_vec_node = this->l_vec;
  for (int l1 = 0; l1 < l_vec_node.size(); l1++) {
    for (int l2 = 0; l2 < l_vec_node[l1].size(); l2++) {
      for (int l3 = 0; l3 < l_vec_node[l1][l2].size(); l3++) {
        for (int l4 = 0; l4 < l_vec_node[l1][l2][l3].size(); l4++) {
          l_vec_node[l1][l2][l3][l4] = -1;
        }
      }
    }
  }
  int index = 0;
  int lpl_node_size = this->Jlpl_mpi_task_dis[my_rank].size();
  // cout << "\t \t My rank : " << my_rank<< "\t lpl_node_size = " <<
  // lpl_node_size << endl;

  for (int i = 0; i < lpl_node_size; i++) {
    int A = this->Jlpl_mpi_task_dis[my_rank][i];
    int l12p = l_state[A].l12p;
    int l3p = l_state[A].l3p;
    int l12 = l_state[A].l12;
    int l3 = l_state[A].l3;
    l_struct_wave l_state_t;
    l_state_t.l12p = l12p;
    l_state_t.l3p = l3p;
    l_state_t.l12 = l12;
    l_state_t.l3 = l3;
    l_state_node.push_back(l_state_t);
    l_vec_node[l12p][l12][l3p][l3] = index;
    Llbar_Ic_R_node.push_back(Llbar_Ic_Reduced[A]);
    Llbar_Ic_R_vec_node.push_back(Llbar_Ic_Red_vec[A]);
    index++;
  }
  if (TpeCom.rank() == 0) {
    std::ofstream file;
    file.open("data/l_state_node.dat");
    file << "l12p \t l12\t l3p\t l3" << endl;
    for (int i = 0; i < l_state_node.size(); i++) {
      file << i << "\t \t : ";
      file << l_state_node[i].l12p << "\t ";
      file << l_state_node[i].l12 << "\t ";
      file << l_state_node[i].l3p << "\t ";
      file << l_state_node[i].l3 << "\t " << endl;
    }
    file.close();
    file.open("data/l_vec_node.dat");
    for (int l1 = 0; l1 < l_vec_node.size(); l1++) {
      for (int l2 = 0; l2 < l_vec_node[l1].size(); l2++) {
        for (int l3 = 0; l3 < l_vec_node[l1][l2].size(); l3++) {
          for (int l4 = 0; l4 < l_vec_node[l1][l2][l3].size(); l4++) {
            int index = l_vec_node[l1][l2][l3][l4];
            file << l1 << "\t " << l2 << "\t " << l3 << "\t " << l4
                 << "\t\t index = " << index << endl;
          }
        }
      }
    }
    file.close();
  }
  TpeCom.barrier();

  cout << "Rank : " << my_rank<< "\t l_state_node.size : " << l_state_node.size() << endl;
  // exit(0);
  // -------------------------------- End --------------------------------- //
  //
  // ------------ Wave : PFKglbarS --------------//
  //
  vector<vector<vector<int>>> lbar_vec_node;
  vector<lbar_struct> lbar_state_node;
  lbar_struct lbar_s_t;
  lbar_vec_node = this->lbar_vec;
  for (int i = 0; i < this->lbar_state.size(); i++) {
    int lbar = this->lbar_state[i].lbar;
    int lbar12 = this->lbar_state[i].lbar12;
    int lbar3 = this->lbar_state[i].lbar3;
    lbar_s_t.lbar = lbar;
    lbar_s_t.lbar12 = lbar12;
    lbar_s_t.lbar3 = lbar3;
    lbar_state_node.push_back(lbar_s_t);
  }
  int Emax_F = jaco.Emax_F;
  int Emax_I = jaco.Emax_I;
  wave.PFKglbarS_init(n_max, lbar_max, Emax_F, Emax_I, E_Jac_conf, l_state_node,
                      l_vec_node, lbar_state_node, lbar_vec_node,
                      Llbar_Ic_R_node, Llbar_Ic_R_vec_node);

  // cout << "Rank : " << my_rank << "\t PFKglbarS_init Finished" << endl;
  cout << "Rank : " << TpeCom.rank()
       << "\t nlpnl_state.size() = " << wave.nlpnl_state.size() << endl;
  // ------------------ End ---------------------//

  // ---------------- build MPI -----------------//
  // c1 c3 c4 term
  this->build_MPI_III();
  // -------------------- End -------------------//
}

void Tpe_term::build_MPI() {
  int ch_size = jaco.channel.size();
  // this->vec.resize(ch_size);
  this->rank_vec1.resize(ch_size);
  this->rank_vec3.resize(ch_size);
  this->rank_vec4.resize(ch_size);
  this->rank_vec134.resize(ch_size);
  this->rank_vec_flag.resize(ch_size);
  this->vec.resize(ch_size);

  if (TpeCom.rank() == 0)
    cout << "Begin to build Tpe term MPI :" << endl;
  for (int i = 0; i < ch_size; i++) {
    int size = jaco.state[i].size();
    rank_vec1[i].resize(size);
    rank_vec3[i].resize(size);
    rank_vec4[i].resize(size);
    rank_vec134[i].resize(size);
    vec[i].resize(size);

    rank_vec_flag[i].resize(size);

    // if(size<1)continue;
    // std::cout << "channel : " << i << endl;
    for (int x = 0; x < size; x++) {
      rank_vec1[i][x].resize(size);
      rank_vec3[i][x].resize(size);
      rank_vec4[i][x].resize(size);
      rank_vec134[i][x].resize(size);
      vec[i][x].resize(size);
      rank_vec_flag[i][x].resize(size);

      for (int y = 0; y < size; y++) {
        rank_vec1[i][x][y] = 0.0;
        rank_vec3[i][x][y] = 0.0;
        rank_vec4[i][x][y] = 0.0;
        rank_vec134[i][x][y] = 0.0;
        vec[i][x][y] = 0.0;

        rank_vec_flag[i][x][y] = 0;
      }
    }
  }
  // boost::mpi::communicator TpeCom;
  // mpi::environment env_tpe;
  // mpi::communicator TpeCom;
  int mpi_size = TpeCom.size();
  int my_rank = TpeCom.rank();

  if (mpi_size != wave.mpi_size) {
    cout << "MPI Wrong !! mpi_size != wave.mpi_size in build_MPI" << endl;
    cout << "mpi_size = " << mpi_size << "\t wave.mpi_size = " << wave.mpi_size
         << endl;
    exit(0);
  }

  int mpi_layer = wave.mpi_layer_PFK_vec[my_rank];

  int rank_task = 0;
  for (int lay = 0; lay < mpi_layer; lay++) {
    int wave_proc = my_rank + lay * mpi_size;
    int proc = nlpnl_Wav2Tpe_vec[wave_proc];
    if (proc < 0)
      continue; // proc = -1 or nlpnl_Tpe
    rank_task++;
  }
  // cout << "Rank = " << my_rank
  //      << "\t Total task = " << this->nlpnl_state_tpe.size()
  //      << "\t my task = " << rank_task << endl;

  /*int pgs_range = mpi_layer; // * ch_size;
  Pgs_Bar pgs;
  pgs.init(pgs_range, 30); */

  vector<int> ch_index, i_index, n_index;
  for (int lay = 0; lay < mpi_layer; lay++) {
    int wave_proc = my_rank + lay * mpi_size;
    int proc = nlpnl_Wav2Tpe_vec[wave_proc];
    if (proc < 0)
      continue; // proc = -1 or nlpnl_Tpe

    int n = proc; // nlpnl_Tpe index
    for (int ch = 0; ch < ch_size; ch++) {
      for (int i = 0; i < Jnlp[n][ch].size(); i++) {
        ch_index.push_back(ch);
        i_index.push_back(i);
        n_index.push_back(n);
      }
    }
  }
  /*cout << "My rank : " << my_rank << "\t on " << TpeEnv.processor_name()
       << "\t\t ch_i size: " << i_index.size() << endl;  */

  /*for (int lay = 0; lay < mpi_layer; lay++) {
    if (TpeCom.rank() == 0)
      pgs.PrintBar(lay);
    int wave_proc = my_rank + lay * mpi_size;
    int proc = nlpnl_Wav2Tpe_vec[wave_proc];
    if (proc < 0)
      continue; // proc = -1 or nlpnl_Tpe
    int n = proc;                             // nlpnl_Tpe index
//#pragma omp parallel for schedule(dynamic, 1) // num_threads(20)
    for (int ch = 0; ch < ch_size; ch++) {
      int pgs_i = lay * ch_size + ch;
#pragma omp parallel for schedule(dynamic, 1)
      for (int i = 0; i < Jnlp[n][ch].size(); i++) { */
  int pgs_range = ch_index.size(); // * ch_size;
  Pgs_Bar pgs;
  pgs.init(pgs_range, 30);
  int task_sum = 0;
  // cout<<"rank "<<TpeCom.rank()<<"\t ch_index.size() :
  // "<<ch_index.size()<<endl;
#pragma omp parallel for schedule(dynamic, 1)
  for (int ch_i_n = 0; ch_i_n < ch_index.size(); ch_i_n++) {
    // if (TpeCom.rank() == 0)
    pgs.PrintBar(task_sum);

    int n = n_index[ch_i_n];
    int ch = ch_index[ch_i_n];
    int i = i_index[ch_i_n];

    int x = Jnlp[n][ch][i].f;
    int y = Jnlp[n][ch][i].i;
    double val1 = this->C1_term2(jaco.state[ch][x], jaco.state[ch][y]);
    // cout << "C1_term : " << val1 << "\t C1_term2 : " << val11 << endl;
    // double val3 = this->C3_term(jaco.state[i][x], jaco.state[i][y]);
    double val3 = this->C3_term2(jaco.state[ch][x], jaco.state[ch][y]);
    // cout << "C3_term : " << val3 << "\t C3_term2 : " << val33 << endl;
    // double val4 = this->C4_term(jaco.state[i][x], jaco.state[i][y]);
    double val4 = this->C4_term2(jaco.state[ch][x], jaco.state[ch][y]);
    // cout << "C4_term : " << val4 << "\t C4_term2 : " << val44 << endl;
    // rank_vec[ch][x][y] = val1 + val3 + val4;
    // vec[ch][y][x] = val1 + val3 + val4;
    rank_vec1[ch][x][y] = val1;
    rank_vec1[ch][y][x] = val1;
    rank_vec3[ch][x][y] = val3;
    rank_vec3[ch][y][x] = val3;
    rank_vec4[ch][x][y] = val4;
    rank_vec4[ch][y][x] = val4;

    rank_vec134[ch][y][x] = val1 + val3 + val4;
    rank_vec134[ch][x][y] = val1 + val3 + val4;

    rank_vec_flag[ch][x][y] = 1;
    rank_vec_flag[ch][y][x] = 1;
    //}
    //}
    task_sum++;
  }
  if (TpeCom.rank() == 0)
    pgs.EndBar();
  if (my_rank == 0) {

    // vector<vector<vector<vector<double>>>> rank0_vec1(mpi_size);
    // vector<vector<vector<vector<double>>>> rank0_vec3(mpi_size);
    // vector<vector<vector<vector<double>>>> rank0_vec4(mpi_size);
    vector<vector<vector<vector<double>>>> rank0_vec134(mpi_size);

    vector<vector<vector<vector<int>>>> rank0_vec_flag(mpi_size);

    // rank0_vec1[0] = this->rank_vec1;
    // rank0_vec3[0] = this->rank_vec3;
    // rank0_vec4[0] = this->rank_vec4;
    rank0_vec134[0] = this->rank_vec134;

    rank0_vec_flag[0] = this->rank_vec_flag;

    for (int rank = 1; rank < mpi_size; rank++) {
      // TpeCom.recv(rank, 11, rank0_vec1[rank]);
      // TpeCom.recv(rank, 33, rank0_vec3[rank]);
      // TpeCom.recv(rank, 44, rank0_vec4[rank]);
      TpeCom.recv(rank, 55, rank0_vec134[rank]);
      TpeCom.recv(rank, 00, rank0_vec_flag[rank]);
    }
    // this->rearrange_vec(rank0_vec1, rank0_vec_flag, vec1);
    // this->rearrange_vec(rank0_vec3, rank0_vec_flag, vec3);
    // this->rearrange_vec(rank0_vec4, rank0_vec_flag, vec4);
    vec.clear();
    this->rearrange_vec(rank0_vec134, rank0_vec_flag, vec);

    cout << " Rank : " << TpeCom.rank() << " -- End Tpe -- " << endl;
  } else {
    // TpeCom.send(0, 11, rank_vec1);
    // TpeCom.send(0, 33, rank_vec3);
    // TpeCom.send(0, 44, rank_vec4);
    TpeCom.send(0, 55, rank_vec134);
    TpeCom.send(0, 00, rank_vec_flag);
    cout << "\t -- rank : " << TpeCom.rank() << " -- End Tpe -- " << endl;
  }
}

void Tpe_term::build_MPI_II() {
  int ch_size = jaco.channel.size();
  // this->vec.resize(ch_size);
  this->rank_vec1.resize(ch_size);
  this->rank_vec3.resize(ch_size);
  this->rank_vec4.resize(ch_size);
  this->rank_vec134.resize(ch_size);
  this->rank_vec_flag.resize(ch_size);
  this->vec.resize(ch_size);

  if (TpeCom.rank() == 0)
    cout << "Begin to build Tpe term MPI :" << endl;
  for (int i = 0; i < ch_size; i++) {
    int size = jaco.state[i].size();
    rank_vec1[i].resize(size);
    rank_vec3[i].resize(size);
    rank_vec4[i].resize(size);
    rank_vec134[i].resize(size);
    vec[i].resize(size);

    rank_vec_flag[i].resize(size);

    // if(size<1)continue;
    // std::cout << "channel : " << i << endl;
    for (int x = 0; x < size; x++) {
      rank_vec1[i][x].resize(size);
      rank_vec3[i][x].resize(size);
      rank_vec4[i][x].resize(size);
      rank_vec134[i][x].resize(size);
      vec[i][x].resize(size);
      rank_vec_flag[i][x].resize(size);

      for (int y = 0; y < size; y++) {
        rank_vec1[i][x][y] = 0.0;
        rank_vec3[i][x][y] = 0.0;
        rank_vec4[i][x][y] = 0.0;
        rank_vec134[i][x][y] = 0.0;
        vec[i][x][y] = 0.0;

        rank_vec_flag[i][x][y] = 0;
      }
    }
  }
  // boost::mpi::communicator TpeCom;
  // mpi::environment env_tpe;
  // mpi::communicator TpeCom;
  int mpi_size = TpeCom.size();
  int my_rank = TpeCom.rank();

  if (mpi_size != wave.mpi_size) {
    cout << "MPI Wrong !! mpi_size != wave.mpi_size in build_MPI" << endl;
    cout << "mpi_size = " << mpi_size << "\t wave.mpi_size = " << wave.mpi_size
         << endl;
    exit(0);
  }

  int mpi_layer = wave.mpi_layer_PFK_vec[my_rank];

  int rank_task = 0;
  for (int lay = 0; lay < mpi_layer; lay++) {
    int wave_proc = my_rank + lay * mpi_size;
    int proc = nlpnl_Wav2Tpe_vec[wave_proc];
    if (proc < 0)
      continue; // proc = -1 or nlpnl_Tpe
    rank_task++;
  }
  // cout << "Rank = " << my_rank
  //      << "\t Total task = " << this->nlpnl_state_tpe.size()
  //      << "\t my task = " << rank_task << endl;

  /*int pgs_range = mpi_layer; // * ch_size;
  Pgs_Bar pgs;
  pgs.init(pgs_range, 30);*/

  vector<int> ch_index, i_index, n_index;
  for (int lay = 0; lay < mpi_layer; lay++) {
    int wave_proc = my_rank + lay * mpi_size;
    int proc = nlpnl_Wav2Tpe_vec[wave_proc];
    if (proc < 0)
      continue; // proc = -1 or nlpnl_Tpe

    int n = proc; // nlpnl_Tpe index
    for (int ch = 0; ch < ch_size; ch++) {
      for (int i = 0; i < Jnlp[n][ch].size(); i++) {
        ch_index.push_back(ch);
        i_index.push_back(i);
        n_index.push_back(n);
      }
    }
  }
  /*cout << "My rank : " << my_rank << "\t on " << TpeEnv.processor_name()
       << "\t\t ch_i size: " << i_index.size() << endl;  */

  /*for (int lay = 0; lay < mpi_layer; lay++) {
    if (TpeCom.rank() == 0)
      pgs.PrintBar(lay);
    int wave_proc = my_rank + lay * mpi_size;
    int proc = nlpnl_Wav2Tpe_vec[wave_proc];
    if (proc < 0)
      continue; // proc = -1 or nlpnl_Tpe
    int n = proc;                             // nlpnl_Tpe index
//#pragma omp parallel for schedule(dynamic, 1) // num_threads(20)
    for (int ch = 0; ch < ch_size; ch++) {
      int pgs_i = lay * ch_size + ch;
#pragma omp parallel for schedule(dynamic, 1)
      for (int i = 0; i < Jnlp[n][ch].size(); i++) { */
  int pgs_range = ch_index.size(); // * ch_size;
  Pgs_Bar pgs;
  pgs.init(pgs_range, 30);
  int task_sum = 0;
  // cout<<"rank "<<TpeCom.rank()<<"\t ch_index.size() :
  // "<<ch_index.size()<<endl;
#pragma omp parallel for schedule(dynamic, 1)
  for (int ch_i_n = 0; ch_i_n < ch_index.size(); ch_i_n++) {
    if (TpeCom.rank() == 0)
      pgs.PrintBar(task_sum);

    int n = n_index[ch_i_n];
    int ch = ch_index[ch_i_n];
    int i = i_index[ch_i_n];

    int x = Jnlp[n][ch][i].f;
    int y = Jnlp[n][ch][i].i;
    double val1 = this->C1_term2(jaco.state[ch][x], jaco.state[ch][y]);
    // cout << "C1_term : " << val1 << "\t C1_term2 : " << val11 << endl;
    // double val3 = this->C3_term(jaco.state[i][x], jaco.state[i][y]);
    double val3 = this->C3_term2(jaco.state[ch][x], jaco.state[ch][y]);
    // cout << "C3_term : " << val3 << "\t C3_term2 : " << val33 << endl;
    // double val4 = this->C4_term(jaco.state[i][x], jaco.state[i][y]);
    double val4 = this->C4_term2(jaco.state[ch][x], jaco.state[ch][y]);
    // cout << "C4_term : " << val4 << "\t C4_term2 : " << val44 << endl;
    // rank_vec[ch][x][y] = val1 + val3 + val4;
    // vec[ch][y][x] = val1 + val3 + val4;
    rank_vec1[ch][x][y] = val1;
    rank_vec1[ch][y][x] = val1;
    rank_vec3[ch][x][y] = val3;
    rank_vec3[ch][y][x] = val3;
    rank_vec4[ch][x][y] = val4;
    rank_vec4[ch][y][x] = val4;

    rank_vec134[ch][y][x] = val1 + val3 + val4;
    rank_vec134[ch][x][y] = val1 + val3 + val4;

    rank_vec_flag[ch][x][y] = 1;
    rank_vec_flag[ch][y][x] = 1;
    //}
    //}
    task_sum++;
  }
  if (TpeCom.rank() == 0)
    pgs.EndBar();
  if (my_rank == 0) {

    // vector<vector<vector<vector<double>>>> rank0_vec1(mpi_size);
    // vector<vector<vector<vector<double>>>> rank0_vec3(mpi_size);
    // vector<vector<vector<vector<double>>>> rank0_vec4(mpi_size);
    vector<vector<vector<vector<double>>>> rank0_vec134(mpi_size);

    vector<vector<vector<vector<int>>>> rank0_vec_flag(mpi_size);

    // rank0_vec1[0] = this->rank_vec1;
    // rank0_vec3[0] = this->rank_vec3;
    // rank0_vec4[0] = this->rank_vec4;
    rank0_vec134[0] = this->rank_vec134;

    rank0_vec_flag[0] = this->rank_vec_flag;

    for (int rank = 1; rank < mpi_size; rank++) {
      // TpeCom.recv(rank, 11, rank0_vec1[rank]);
      // TpeCom.recv(rank, 33, rank0_vec3[rank]);
      // TpeCom.recv(rank, 44, rank0_vec4[rank]);
      TpeCom.recv(rank, 55, rank0_vec134[rank]);
      TpeCom.recv(rank, 00, rank0_vec_flag[rank]);
    }
    // this->rearrange_vec(rank0_vec1, rank0_vec_flag, vec1);
    // this->rearrange_vec(rank0_vec3, rank0_vec_flag, vec3);
    // this->rearrange_vec(rank0_vec4, rank0_vec_flag, vec4);
    vec.clear();
    this->rearrange_vec(rank0_vec134, rank0_vec_flag, vec);

    cout << " Rank : " << TpeCom.rank() << " -- End Tpe -- " << endl;
  } else {
    // TpeCom.send(0, 11, rank_vec1);
    // TpeCom.send(0, 33, rank_vec3);
    // TpeCom.send(0, 44, rank_vec4);
    TpeCom.send(0, 55, rank_vec134);
    TpeCom.send(0, 00, rank_vec_flag);
    cout << "\t -- rank : " << TpeCom.rank() << " -- End Tpe -- " << endl;
  }
}

void Tpe_term::build_MPI_III() {
  int ch_size = jaco.channel.size();
  // this->vec.resize(ch_size);
  this->rank_vec1.resize(ch_size);
  this->rank_vec3.resize(ch_size);
  this->rank_vec4.resize(ch_size);
  this->rank_vec134.resize(ch_size);
  this->rank_vec_flag.resize(ch_size);
  this->vec.resize(ch_size);

  if (TpeCom.rank() == 0)
    cout << "Begin to build Tpe term MPI_III :" << endl;
  for (int i = 0; i < ch_size; i++) {
    int size = jaco.state[i].size();
    rank_vec1[i].resize(size);
    rank_vec3[i].resize(size);
    rank_vec4[i].resize(size);
    rank_vec134[i].resize(size);
    vec[i].resize(size);

    rank_vec_flag[i].resize(size);

    // if(size<1)continue;
    // std::cout << "channel : " << i << endl;
    for (int x = 0; x < size; x++) {
      rank_vec1[i][x].resize(size);
      rank_vec3[i][x].resize(size);
      rank_vec4[i][x].resize(size);
      rank_vec134[i][x].resize(size);
      vec[i][x].resize(size);
      rank_vec_flag[i][x].resize(size);

      for (int y = 0; y < size; y++) {
        rank_vec1[i][x][y] = 0.0;
        rank_vec3[i][x][y] = 0.0;
        rank_vec4[i][x][y] = 0.0;
        rank_vec134[i][x][y] = 0.0;
        vec[i][x][y] = 0.0;

        rank_vec_flag[i][x][y] = 0;
      }
    }
  }
  // boost::mpi::communicator TpeCom;
  // mpi::environment env_tpe;
  // mpi::communicator TpeCom;
  int mpi_size = TpeCom.size();
  int my_rank = TpeCom.rank();
  int l_dis_size = Jlpl_mpi_task_dis[my_rank].size();
  int flag = 1;
  TpeCom.barrier();
  // for (int rank = 0; rank < mpi_size; rank++) {
  //   //
  //   TpeCom.barrier();
  //   if (my_rank == rank) {
  //     cout << "My rank : " << my_rank << "\t on " << TpeEnv.processor_name();
  //     for (int i = 0; i < l_dis_size; i++) {
  //       int l = Jlpl_mpi_task_dis[my_rank][i];
  //       cout << "\t l_state : " << l << "(" << Jlpl_mpi_task_all[l] << ")";
  //     }
  //     cout << endl;
  //   }
  //   //
  // }
  TpeCom.barrier();

  vector<int> l_index, ch_index, i_index;
  int index_ch_l_i = 0;
  for (int ld = 0; ld < l_dis_size; ld++) {
    int l = Jlpl_mpi_task_dis[my_rank][ld];
    int size_ch = Jlpl[l].size();
    for (int ch = 0; ch < ch_size; ch++) {
      int size_i = Jlpl[l][ch].size();
      for (int i = 0; i < size_i; i++) {
        l_index.push_back(l);
        ch_index.push_back(ch);
        i_index.push_back(i);
        index_ch_l_i++;
      }
    }
  }

  int pgs_range = ch_index.size(); // * ch_size;
  Pgs_Bar pgs;
  pgs.init(pgs_range, 30);
  int task_sum = 0;
  // cout<<"rank "<<TpeCom.rank()<<"\t ch_index.size() :
  // "<<ch_index.size()<<endl;
#pragma omp parallel for schedule(dynamic, 1)
  for (int ch_l_i = 0; ch_l_i < ch_index.size(); ch_l_i++) {
    // if (TpeCom.rank() == 0)
    //  pgs.PrintBar(task_sum);

    int l = l_index[ch_l_i];
    int ch = ch_index[ch_l_i];
    int i = i_index[ch_l_i];

    int x = Jlpl[l][ch][i].f;
    int y = Jlpl[l][ch][i].i;

    // if (TpeCom.rank() == check_node) {
    //   cout << "### -- ### l:" << l << "\t ch:" << ch << "\t x:" << x
    //        << "\t y:" << y << endl;
    // }

    double val1 = this->C1_term2(jaco.state[ch][x], jaco.state[ch][y]);
    // cout << "C1_term : " << val1 << "\t C1_term2 : " << val11 << endl;
    // double val3 = this->C3_term(jaco.state[i][x], jaco.state[i][y]);
    double val3 = this->C3_term2(jaco.state[ch][x], jaco.state[ch][y]);
    // cout << "C3_term : " << val3 << "\t C3_term2 : " << val33 << endl;
    // double val4 = this->C4_term(jaco.state[i][x], jaco.state[i][y]);
    double val4 = this->C4_term2(jaco.state[ch][x], jaco.state[ch][y]);
    // cout << "C4_term : " << val4 << "\t C4_term2 : " << val44 << endl;
    // rank_vec[ch][x][y] = val1 + val3 + val4;
    // vec[ch][y][x] = val1 + val3 + val4;
    if (ch == 0 && x == 283 && y == 327) {
      cout << endl;
      cout << "\t\t CHECK on NODE : " << TpeCom.rank() << endl;
      cout << "\t \t val_1 = " << val1 << "\t val3 = " << val3
           << "\t val4 = " << val4 << endl;
      cout << endl;
      cout << endl;
      // double val_check = this->C1_term2_check(jaco.state[ch][x],
      // jaco.state[ch][y]); double val_check2 =
      // this->C3_term2_check(jaco.state[ch][x], jaco.state[ch][y]); double
      // val_check3 = this->C4_term2_check(jaco.state[ch][x], jaco.state[ch][y]);
    }
    rank_vec1[ch][x][y] = val1;
    rank_vec1[ch][y][x] = val1;
    rank_vec3[ch][x][y] = val3;
    rank_vec3[ch][y][x] = val3;
    rank_vec4[ch][x][y] = val4;
    rank_vec4[ch][y][x] = val4;

    rank_vec134[ch][y][x] = val1 + val3 + val4;
    rank_vec134[ch][x][y] = val1 + val3 + val4;

    rank_vec_flag[ch][x][y] = 1;
    rank_vec_flag[ch][y][x] = 1;
    //}
    //}
    task_sum++;
  }
  if (TpeCom.rank() == 0)
    pgs.EndBar();
  if (my_rank == 0) {

    // vector<vector<vector<vector<double>>>> rank0_vec1(mpi_size);
    // vector<vector<vector<vector<double>>>> rank0_vec3(mpi_size);
    // vector<vector<vector<vector<double>>>> rank0_vec4(mpi_size);
    vector<vector<vector<vector<double>>>> rank0_vec134(mpi_size);

    vector<vector<vector<vector<int>>>> rank0_vec_flag(mpi_size);

    // rank0_vec1[0] = this->rank_vec1;
    // rank0_vec3[0] = this->rank_vec3;
    // rank0_vec4[0] = this->rank_vec4;
    rank0_vec134[0] = this->rank_vec134;

    rank0_vec_flag[0] = this->rank_vec_flag;

    for (int rank = 1; rank < mpi_size; rank++) {
      // TpeCom.recv(rank, 11, rank0_vec1[rank]);
      // TpeCom.recv(rank, 33, rank0_vec3[rank]);
      // TpeCom.recv(rank, 44, rank0_vec4[rank]);
      TpeCom.recv(rank, 55, rank0_vec134[rank]);
      TpeCom.recv(rank, 00, rank0_vec_flag[rank]);
    }
    // this->rearrange_vec(rank0_vec1, rank0_vec_flag, vec1);
    // this->rearrange_vec(rank0_vec3, rank0_vec_flag, vec3);
    // this->rearrange_vec(rank0_vec4, rank0_vec_flag, vec4);
    vec.clear();
    this->rearrange_vec(rank0_vec134, rank0_vec_flag, vec);

    cout << " Rank : " << TpeCom.rank() << " -- End Tpe -- " << endl;
  } else {
    // TpeCom.send(0, 11, rank_vec1);
    // TpeCom.send(0, 33, rank_vec3);
    // TpeCom.send(0, 44, rank_vec4);
    TpeCom.send(0, 55, rank_vec134);
    TpeCom.send(0, 00, rank_vec_flag);
    cout << "\t -- rank : " << TpeCom.rank() << " -- End Tpe -- " << endl;
  }
}

void Tpe_term::rearrange_vec(
    vector<vector<vector<vector<double>>>> &rank0_vec,
    vector<vector<vector<vector<int>>>> &rank0_vec_flag,
    vector<vector<vector<double>>> &vec_out) {
  int size_rank = rank0_vec.size();
  if (size_rank < 1) {
    cout << "Wrong at Tpe_term::rearrange_vec" << endl;
    exit(0);
  }
  int size_channel = rank0_vec[0].size();
  // cout << "size_channel = " << size_channel << "\t size_rank = " <<
  // size_rank
  //     << endl;
  // vector<vector<vector<int>>> vec_flag_tot;
  vec_out.resize(size_channel);

  this->vec_flag_tot.resize(size_channel);
  for (int ch = 0; ch < size_channel; ch++) {
    int xy_size = rank0_vec[0][ch].size();
    vec_out[ch].resize(xy_size);
    vec_flag_tot[ch].resize(xy_size);

    for (int x = 0; x < xy_size; x++) {
      vec_out[ch][x].resize(xy_size);
      this->vec_flag_tot[ch][x].resize(xy_size);
      for (int y = 0; y < xy_size; y++) {
        this->vec_flag_tot[ch][x][y] = 0;
      }
    }
  }

  for (int r = 0; r < size_rank; r++) {
    for (int ch = 0; ch < size_channel; ch++) {
      int xy_size = rank0_vec[0][ch].size();
      for (int x = 0; x < xy_size; x++) {
        for (int y = 0; y < xy_size; y++) {
          // cout << "r : " << r << "\t ch: " << ch << "\t " << x << "\t" << y
          //      << "\t" << rank0_vec_flag[r][ch][x][y] << endl;
          if (rank0_vec_flag[r][ch][x][y] == 1) {
            // if (vec_flag_tot[ch][x][y] == 1 && x != y) {
            //   cout << "Something Wrong happend in Tpe_term::rearrange_vec
            //   1"
            //        << endl;
            //   exit(0);
            // }

            double val = rank0_vec[r][ch][x][y];
            vec_out[ch][x][y] = val;
            vec_out[ch][y][x] = val;
            this->vec_flag_tot[ch][x][y] = 1;
            this->vec_flag_tot[ch][y][x] = 1;
            // cout << ch << "\t" << x << "\t" << y << vec_flag_tot[ch][x][y]
            //     << endl;
          }
        }
      }
    }
  }
  // exit(0);

  // check to see if arranged well
  std::string filename = "data/arrange_check.dat";
  std::ofstream file;
  file.open(filename);
  for (int ch = 0; ch < size_channel; ch++) {
    int xy_size = rank0_vec[0][ch].size();
    file << " === channel : " << ch << " === " << endl;
    for (int x = 0; x < xy_size; x++) {
      int Par_p = this->phase(jaco.state[ch][x].l12 + jaco.state[ch][x].l3);
      int E_p = jaco.state[ch][x].E;

      for (int y = 0; y < xy_size; y++) {
        int Par = this->phase(jaco.state[ch][y].l12 + jaco.state[ch][y].l3);
        int E = jaco.state[ch][y].E;

        if (vec_flag_tot[ch][x][y] != 1 && Par_p == Par && E_p == E) {
          /*cout << "Something Wrong happend in Tpe_term::rearrange_vec 2"
               << endl;
          cout << "Problem Channel = " << ch << "\t " << x << "\t" << y <<
          endl;
           *///  exit(0);
        }
        file << x << "\t" << y << "\t\t" << vec_flag_tot[ch][x][y] << endl;
      }
    }
  }
  file.close();
  // exit(0);
}

void Tpe_term::print(int ch_num) {
  int size = vec[ch_num].size();
  for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) {
      if (vec[ch_num][i][j] != 0.0)
        cout << i << "\t" << j << "\t" << vec[ch_num][i][j] << endl;
    }
  }
}
void Tpe_term::print() {
  for (int ch_num = 0; ch_num < vec.size(); ch_num++) {
    int size = vec[ch_num].size();
    cout << "channel num : " << ch_num << endl;
    for (int i = 0; i < size; i++) {
      for (int j = 0; j < size; j++) {
        if (std::abs(vec[ch_num][i][j]) > 0.0001)
          // cout << i << "\t" << j << "\t" << vec1[ch_num][i][j] << "\t"
          //      << vec3[ch_num][i][j] << "\t" << vec4[ch_num][i][j] << endl;
          cout << i << "\t" << j << "\t" << vec[ch_num][i][j] << endl;
      }
    }
  }
}

void Tpe_term::Task_Distr(vector<int> jobs, int Nodes,
                          vector<vector<int>> &dis_task) {
  // Task Distribution
  int print_flag = -1;
  // Sort by size
  int size_j = jobs.size();
  vector<element_Task_dis> jobs_vec, jobs_vec_ori;
  element_Task_dis jobs_t;
  int Total_Jobs = 0;
  for (int i = 0; i < size_j; i++) {
    jobs_t.index = i;
    jobs_t.data = jobs[i];
    jobs_vec.push_back(jobs_t);
    Total_Jobs += jobs[i];
  }
  int Average_Jobs = Total_Jobs / Nodes + 1;
  vector<int> tot_task(Nodes);
  for (int i = 0; i < size_j; i++) {
    if (print_flag > 0) {
      if (i % Nodes == 0)
        cout << endl;
      cout << jobs_vec[i].index << " ( " << jobs_vec[i].data << " ) \t";
    }
    int j = i % Nodes;
    tot_task[j] += jobs_vec[i].data;
  }
  if (print_flag > 0) {
    cout << endl;

    for (int i = 0; i < Nodes; i++) {
      cout << tot_task[i] << "\t \t ";
    }
    cout << endl;
  }
  jobs_vec_ori = jobs_vec;
  stable_sort(
      jobs_vec.begin(), jobs_vec.end(),
      [](element_Task_dis a, element_Task_dis b) { return a.data > b.data; });

  vector<element_Task_dis> jobs_count(Nodes);
  for (int i = 0; i < Nodes; i++) {
    jobs_count[i].index = i;
    jobs_count[i].data = 0;
  }
  dis_task.resize(Nodes);

  int flag = 0;
  int flag_A = 0;
  int flag_B = 1;
  int i = 0;
  while (i < size_j) {
    if (flag % Nodes == 0) {
      stable_sort(jobs_count.begin(), jobs_count.end(),
                  [](element_Task_dis a, element_Task_dis b) {
                    return a.data <= b.data;
                  });
    }
    int j = flag % Nodes;
    if ((jobs_count[j].data + jobs_vec[i].data) > Average_Jobs &&
        (flag_B > 0)) {
      flag++;
      flag_A++;
      if (flag_A < Nodes) {
        continue;
      } else {
        flag = 0;
        flag_B = -1;
        continue;
      }
    }
    jobs_count[j].data += jobs_vec[i].data;
    int index_origine = jobs_vec[i].index;
    int index_Nodes = jobs_count[j].index;
    dis_task[index_Nodes].push_back(index_origine);
    i += 1;
    flag++;
    flag_A = 0;
    flag_B = 1;
    // cout<<i<<endl;
  }

  for (int i = 0; i < Nodes; i++) {
    int num = 0;
    for (int j = 0; j < dis_task[i].size(); j++) {
      int A = dis_task[i][j];
      // cout << jobs_vec[A].index << " ( " << jobs_vec[A].data << " ) \t";
      if (print_flag > 0)
        cout << A << " ( " << jobs[A] << " ) \t";
      num += jobs[A];
    }
    if (print_flag > 0)
      cout << "\t Tot : " << num << endl;
  }
}

void Tpe_term::print(std::string filename) {
  std::ofstream file;
  file.open(filename);
  for (int ch_num = 0; ch_num < vec.size(); ch_num++) {
    int size = vec[ch_num].size();
    file << "channel num : " << ch_num << endl;
    file << "i\t j\t C1_term\t C3_term\t C4_term" << endl;
    for (int i = 0; i < size; i++) {
      for (int j = 0; j < size; j++) {
        if (vec[ch_num][i][j] != 0.0)
          // file << i << "\t" << j << "\t" << vec1[ch_num][i][j] << "\t"
          //      << vec3[ch_num][i][j] << "\t" << vec4[ch_num][i][j] << endl;
          file << i << "\t" << j << "\t" << vec[ch_num][i][j] << endl;
      }
    }
  }
  file.close();
}
